首次出现在斯特恩的双原子序列中

2024-02-28

你得到一个整数n,你需要找到它在斯特恩双原子序列中第一次出现的索引。

序列定义如下:

a[0]     = 0
a[1]     = 1
a[2*i]   = a[i]
a[2*i+1] = a[i] + a[i+1]

See 数学世界 http://mathworld.wolfram.com/SternsDiatomicSeries.html.

由于 n 最大可达 400000,因此暴力破解它并不是一个好主意,特别是因为时间限制为 4000 毫秒。

这个序列非常奇怪:第一次出现 8 是 21,但第一次出现 6 是 33。

有什么想法如何解决这个问题吗?

也许这可能有帮助:OEIS http://oeis.org/A020946


我们可以在四秒内轻松解决 400000 范围内的数字第一次出现的问题:

Prelude Diatomic> firstDiatomic 400000
363490989
(0.03 secs, 26265328 bytes)
Prelude Diatomic> map firstDiatomic [400000 .. 400100]
[363490989,323659475,580472163,362981813,349334091,355685483,346478235,355707595
,291165867,346344083,347155797,316314293,576398643,315265835,313171245,355183267
,315444051,315970205,575509833,311741035,340569429,313223987,565355925,296441165
,361911645,312104147,557145429,317106853,323637939,324425077,610613547,311579309
,316037811,311744107,342436533,348992869,313382235,325406123,355818699,312128723
,347230875,324752171,313178421,312841811,313215645,321754459,576114987,325793195
,313148763,558545581,355294101,359224397,345462093,307583675,355677549,312120731
,341404245,316298389,581506779,345401947,312109779,316315061,315987123,313447771
,361540179,313878107,304788843,325765547,316036275,313731751,355635795,312035947
,346756533,313873883,349358379,357393763,559244877,313317739,325364139,312128107
,580201947,358182323,314944173,357403987,584291115,312158827,347448723,363246413
,315935571,349386085,315929427,312137323,357247725,313207657,320121429,356954923
,557139285,296392013,576042123,311726765,296408397]
(2.45 secs, 3201358192 bytes)

它的关键是 Calkin-Wilf 树。

从分数开始1/1,它的构建规则是对于具有分数的节点a/b,它的左孩子携带分数a/(a+b),及其右子分数(a+b)/b.

                        1/1
                       /   \
                      /     \
                     /       \
                  1/2         2/1
                 /   \       /   \
               1/3   3/2   2/3   3/1

双原子序列(从索引 1 开始)是 Calkin-Wilf 树中分数的分子序列,当从左到右逐层遍历时。

如果我们看一下索引树

                         1
                        / \
                       /   \
                      /     \
                     2       3
                    / \     / \
                   4   5   6   7
                  / \ 
                 8   9 ...

我们可以很容易地验证索引处的节点kCalkin-Wilf 树中带有分数a[k]/a[k+1]通过感应。

这显然是正确的k = 1 (a[1] = a[2] = 1),从那时起,

  • for k = 2*j我们有带有索引的节点的左子节点j,所以分数是a[j]/(a[j]+a[j+1]) and a[k] = a[j] and a[k+1] = a[j] + a[j+1]是序列的定义方程。

  • for k = 2*j+1我们有带有索引的节点的右子节点j,所以分数是(a[j]+a[j+1])/a[j+1]那就是a[k]/a[k+1]再次通过定义方程。

所有正约化分数在 Calkin-Wilf 树中只出现一次(留给读者作为练习),因此所有正整数都出现在双原子序列中。

我们可以通过索引的二进制表示从索引中找到 Calkin-Wilf 树中的节点,从最高有效位到最低有效位,对于 1 位,我们转到右子节点,对于 0 位,我们转到右子节点。左边。 (为此,最好用一个节点来扩充 Calkin-Wilf 树0/1谁的右孩子是1/1节点,因此我们需要对索引的最高有效设置位进行一步。)

现在,这对于解决当前的问题还没有多大帮助。

但是,让我们首先解决一个相关问题:对于约化分数p/q,确定其索引。

假设p > q。然后我们知道p/q是一个右孩子,它的父母是(p-q)/q。如果还有p-q > q,我们又有一个右孩子,其父母是(p - 2*q)/q。继续,如果

p = a*q + b, 1 <= b < q

然后我们到达p/q节点从b/q通过转到右子节点a times.

现在我们需要找到一个分子小于分母的节点。那当然是其父母的左孩子。的父母b/q is b/(q-b)然后。如果

q = c*b + d, 1 <= d < b

我们必须去找左边的孩子c距离节点的时间b/d达到b/q.

等等。

我们可以从根源上找到路(1/1)到p/q节点使用连分数(我这里只考虑简单的连分数)展开p/q. Let p > q and

p/q = [a_0, a_1, ..., a_r,1]

的连续分数展开式p/q结束于1.

  • If r是偶数,则去右边的孩子a_r次,然后向左a_(r-1)次,然后给正确的孩子......然后a_1次到左边的孩子,最后a_0次向右。
  • If r是奇数,那么先去左边的孩子a_r次,那么a_(r-1)向右...然后a_1次到左边的孩子,最后a_0次向右。

For p < q,我们必须结束向左移动,因此开始向左移动r并开始向右走奇数r.

因此,我们发现索引的二进制表示与节点通过从根到节点的路径所携带的分数的连续分数展开之间存在紧密的联系。

让索引的游程编码k be

[c_1, c_2, ..., c_j]           (all c_i > 0)

即二进制表示k以。。开始c_1的,然后是c_2零,那么c_3等等,并以c_j

  • 那些,如果k是奇数 - 因此j也是奇数;
  • 零,如果k是偶数 - 因此j也是均匀的。

Then [c_j, c_(j-1), ..., c_2, c_1]是连续分式展开式a[k]/a[k+1]其长度具有相同的奇偶性k(每个有理数恰好有两个连分数展开式,一个具有奇数长度,另一个具有偶数长度)。

RLE 给出了从0/1上面的节点1/1 to a[k]/a[k+1]。路径的长度是

  1. 表示所需的位数k, and
  2. 连分数展开式中的部分商之和。

现在,找到第一次出现的索引n > 0在双原子序列中,我们首先观察到最小的索引必然是奇数,因为a[k] = a[k/2]对于甚至k。设最小索引为k = 2*j+1. Then

  1. 角色的长度k is odd,
  2. 具有索引的节点处的分数k is a[2*j+1]/a[2*j+2] = (a[j] + a[j+1])/a[j+1],因此它是一个右孩子。

所以最小的索引k with a[k] = n对应于分子节点的所有最短路径的最左端n.

最短路径对应于连续分数展开式n/m, where 0 < m <= n互质于n[必须减少分数]与最小的部分商之和。

我们需要期望什么样的长度?给定一个连分数p/q = [a_0, a_1, ..., a_r] with a_0 > 0 and sum

s = a_0 + ... + a_r

分子p的边界是F(s+1)和分母q by F(s), where F(j) is the j-th 斐波那契数。边界是尖锐的,因为a_0 = a_1 = ... = a_r = 1分数是F(s+1)/F(s).

So if F(t) < n <= F(t+1),连分数展开式(两者之一)的部分商之和为>= t。经常有一个m使得连分数展开式的部分商之和n/m正是t, 但不总是:

F(5) = 5 < 6 <= F(6) = 8

以及两个约简分数的连分数展开式6/m with 0 < m <= 6 are

6/1 = [6]          (alternatively [5,1])
6/5 = [1,4,1]      (alternatively [1,5])

部分商之和为 6。然而,最小可能的部分商之和永远不会大很多(我知道的最大的是t+2).

的连续分数展开n/m and n/(n-m)密切相关。我们假设m < n/2, 然后让

n/m = [a_0, a_1, ..., a_r]

Then a_0 >= 2,

(n-m)/m = [a_0 - 1, a_1, ..., a_r]

自从

n/(n-m) = 1 + m/(n-m) = 1 + 1/((n-m)/m)

的连续分数展开式n/(n-m) is

n/(n-m) = [1, a_0 - 1, a_1, ..., a_r]

特别是,两者的部分商之和是相同的。

不幸的是,我不知道如何找到m具有最小的部分商之和,无需暴力破解,所以该算法是(我假设n > 2

  1. for 0 < m < n/2互质于n,求出连分式展开式n/m,收集部分商之和最小的那些(通常的算法产生的展开式的最后一个部分商是> 1,我们假设)。

  2. 按以下方式调整找到的连分数展开式[数量不大]:

    • 如果CF[a_0, a_1, ..., a_r]长度为偶数,将其转换为[a_0, a_1, ..., a_(r-1), a_r - 1, 1]
    • 否则,使用[1, a_0 - 1, a_1, ..., a_(r-1), a_r - 1, 1]

    (选择其中之一n/m and n/(n-m)导致较小的索引)

  3. 反转连分数以获得相应索引的游程长度编码

  4. 选择其中最小的。

在步骤 1 中,使用迄今为止找到的最小和来进行捷径是有用的。

代码(Haskell,因为这是最简单的):

module Diatomic (diatomic, firstDiatomic, fuscs) where

import Data.List

strip :: Int -> Int -> Int
strip p = go
  where
    go n = case n `quotRem` p of
             (q,r) | r == 0    -> go q
                   | otherwise -> n

primeFactors :: Int -> [Int]
primeFactors n
    | n < 1             = error "primeFactors: non-positive argument"
    | n == 1            = []
    | n `rem` 2 == 0    = 2 : go (strip 2 (n `quot` 2)) 3
    | otherwise         = go n 3
      where
        go 1 _ = []
        go m p
            | m < p*p   = [m]
            | r == 0    = p : go (strip p q) (p+2)
            | otherwise = go m (p+2)
              where
                (q,r) = m `quotRem` p

contFracLim :: Int -> Int -> Int -> Maybe [Int]
contFracLim = go []
  where
    go acc lim n d = case n `quotRem` d of
                       (a,b) | lim < a -> Nothing
                             | b == 0  -> Just (a:acc)
                             | otherwise -> go (a:acc) (lim - a) d b

fixUpCF :: [Int] -> [Int]
fixUpCF [a]
    | a < 3     = [a]
    | otherwise = [1,a-2,1]
fixUpCF xs
    | even (length xs) = case xs of
                           (1:_) -> fixEnd xs
                           (a:bs) -> 1 : (a-1) : bs
    | otherwise        = case xs of
                           (1:_) -> xs
                           (a:bs) -> 1 : fixEnd ((a-1):bs)

fixEnd :: [Int] -> [Int]
fixEnd [a,1] = [a+1]
fixEnd [a] = [a-1,1]
fixEnd (a:bs) = a : fixEnd bs
fixEnd _ = error "Shouldn't have called fixEnd with an empty list"

cfCompare :: [Int] -> [Int] -> Ordering
cfCompare (a:bs) (c:ds) = case compare a c of
                            EQ -> cfCompare ds bs
                            cp -> cp

fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

toNumber :: [Int] -> Integer
toNumber = foldl' ((+) . (*2)) 0 . concat . (flip (zipWith replicate) $ cycle [1,0])

fuscs :: Integer -> (Integer, Integer)
fuscs 0 = (0,1)
fuscs 1 = (1,1)
fuscs n = case n `quotRem` 2 of
            (q,r) -> let (a,b) = fuscs q
                     in if r == 0
                          then (a,a+b)
                          else (a+b,b)
diatomic :: Integer -> Integer
diatomic = fst . fuscs

firstDiatomic :: Int -> Integer
firstDiatomic n
    | n < 0     = error "Diatomic sequence has no negative terms"
    | n < 2     = fromIntegral n
    | n == 2    = 3
    | otherwise = toNumber $ bestCF n

bestCF :: Int -> [Int]
bestCF n = check [] estimate start
  where
    pfs = primeFactors n
    (step,ops) = case pfs of
                   (2:xs) -> (2,xs)
                   _      -> (1,pfs)
    start0 = (n-1) `quot` 2
    start | even n && even start0 = start0 - 1
          | otherwise             = start0
    eligible k = all ((/= 0) . (k `rem`)) ops
    estimate = length (takeWhile (<= fromIntegral n) fibs) + 2
    check candidates lim k
        | k < 1 || n `quot` k >= lim = if null candidates
                                         then check [] (2*lim) start
                                         else minimumBy cfCompare candidates
        | eligible k = case contFracLim lim n k of
                         Nothing -> check candidates lim (k-step)
                         Just cf -> let s = sum cf
                                    in if s < lim
                                         then check [fixUpCF cf] s (k - step)
                                         else check (fixUpCF cf : candidates) lim (k-step)
        | otherwise = check candidates lim (k-step)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

首次出现在斯特恩的双原子序列中 的相关文章

  • 关于合并排序代码中的组合步骤的困惑

    我有一个关于数组上的合并排序如何工作的问题 我理解 划分 步骤 它将输入数组划分为 1 长度的元素 然而 当谈到 合并 部分 组合步骤 时 我感到困惑 例如 给定输入 3 5 1 8 2 除法过程将产生 5 个元素 3 5 1 8 2 我只
  • 硬币兑换的空间优化解决方案

    给定一个值 N 如果我们想要找 N 分钱 并且我们有无限供应每种 S S1 S2 Sm 价值的硬币 我们可以有多少种找零方式 硬币的顺序并不重要 例如 对于 N 4 且 S 1 2 3 有四种解 1 1 1 1 1 1 2 2 2 1 3
  • 以与版本页面上相同的方式区分两个字符串的算法是什么?

    我正在尝试按短语区分两个字符串 类似于 StackOverflow 在版本编辑页面上区分两个字符串的方式 执行此操作的算法是什么 是否有 gems 或其他标准库可以实现此目的 编辑 我见过其他比较算法 Differ http github
  • 如何使用哈希表在最小堆上实现 O(1) 删除

    在某处阅读以下声明 可以使用附加的哈希表来快速删除 最小堆 问题 gt 如何组合priority queue and unordered map这样我就可以实现上面的想法了 include
  • 如何检查一个盒子是否适合另一个盒子(允许任何旋转)

    假设我有两个盒子 每个盒子都是一个长方体 http en wikipedia org wiki Rectangular cuboid aka长方体 我需要编写一个函数来决定盒子是否具有尺寸 一 二 三 可以装入具有尺寸的盒子中 甲 乙 丙
  • 算法:最大计数器

    我有以下问题 您有 N 个计数器 最初设置为 0 并且您对它们有两种可能的操作 increase X 计数器 X 加 1 max counter 所有计数器都设置为任何计数器的最大值 给出一个包含 M 个整数的非空零索引数组 A 该数组代表
  • C# 计算LRC(纵向冗余检查)

    我一直在到处研究这个问题 所有 LRC 实现似乎都没有给我正确的答案 花了几天时间后 我决定将我的代码放在这里 看看其他人是否可以发现问题 这是代码 C Input Data 31303030315E315E31303030325E315E
  • 在 O(n) 时间内运行的指数乘法算法?

    我正在读一本算法教科书 我被这个问题难住了 假设我们要计算值 x y 其中 x 和 y 为正数 分别具有 m 和 n 位的整数 解决该问题的一种方法是执行 y 1 乘以 x 你能给出一个仅使用 O n 乘法步骤的更有效的算法吗 这会是一个分
  • 添加到数组连续数字

    这是我向SO提出的第一个问题 我希望能答对 在 PHP 中 如果你不会 Python 或伪语言也可以 给定一个包含 n 个元素的数组 old array 1 2 3 5 7 8 9 20 21 23 29 我需要向新数组添加连续数字 如果不
  • 为无向无权图实现推重标签算法 s-t 最小割边

    我正在寻找一个好的解决方案来在无向和未加权图中找到 s t 最小切割边 我想使用推送重新标记算法 但我不确定如何实现它以在无向和未加权图上找到最小割 在每对顶点之间有两条反向边 并在所有边上赋予相同的权重 并应用推送重新标记算法 我可以用这
  • 以一定角度遍历二维数组

    通常我们按行或列遍历数组 但这里我想以角度遍历它 我会尝试解释我的意思 因此 假设角度是 45 度 那么它会搜索为 0 0 then 0 1 1 0 then 0 2 1 1 2 0 等等 抱歉 无法上传图像 因为我是新用户 不允许这样做
  • 如何设置K-means openCV c++的初始中心

    我正在尝试使用 OpenCv 和 Kmeans 对图像进行分割 我刚刚实现的代码如下 include opencv2 objdetect objdetect hpp include opencv2 highgui highgui hpp i
  • 如何在Scala中实现尾递归快速排序

    我写了一个递归版本 def quickSort T xs List T p T T gt Boolean List T xs match case Nil gt Nil case gt val x xs head val left righ
  • 加密成本高,解密成本低

    我希望该用户 攻击者加密数据并发送给服务器 现在我想要一种与标准算法完全相反的算法 使用快 难以解密 即很难使用服务器发送的密钥来加密密码等数据 以防止随机攻击 但很容易解密这样服务器在验证用户时消耗的时间非常少 但是对于攻击者来说 每次使
  • 合并字符数组中的最小重复次数

    假设我有两个数组 我想合并它们 以便合并后的数组具有最小重复次数 例如 x x 是重复 arr1 x d d m f m arr2 d d x f f m 唯一的条件是在合并数组中 元素来自arr1 and arr2必须出现在各自的订单中a
  • Exposé 布局算法

    我正在制作一些项目 其布局类似于 Mac OS X 在 Expos 中对窗口所做的操作 它适应项目的长宽比和可用区域的长宽比 基本上 可用区域分为行和列 每个单元格 行和列的交集 中放置一个项目 这些项目必须保持其纵横比 此处width h
  • 如何在给定目标索引数组的情况下对数组进行就地排序?

    你如何对给定的数组进行排序arr in place给定目标索引数组ind 例如 var arr A B C D E F var ind 4 0 5 2 1 3 rearrange arr ind console log arr gt B E
  • 如何查找给定字符串中仅出现一次的第一个字符[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何求解:T(n) = T(n - 1) + n

    我已经解决了以下问题 T n T n 1 n O n 2 现在 当我解决这个问题时 我发现界限非常松散 我是否做错了什么 或者只是这样 您还需要一个递归关系的基本情况 T 1 c T n T n 1 n 为了解决这个问题 您可以首先猜测一个
  • 确定解决迷宫问题的最小线段数

    我有一个问题 我需要定义一个具有最少数量的顶点的多边形 该多边形与不透明的图像中的每个像素相交或包含每个像素 令 N 为图像中的像素数 我唯一的假设是图像的边界 孔 内不能包含透明像素 并且至少有两个像素是不透明的 举个例子 假设我有以下图

随机推荐

  • 测试数字是否在循环区间内

    假设我们有一个数字圈 范围从 180 到 180 看起来像这样 180 180 90 90 0 圆的一部分始终沿顺时针方向扫过 如何判断一个数字是在扫描区间之内还是之外 在以下示例 I O 中 前两个数字表示间隔 第三个数字是正在检查的数字
  • 使用selenium webdriver java 4.0v捕获网络流量

    我想捕获 Chromedriver 窗口中生成的网络流量 我发现可以使用 selenium 4 0 DevTools 实用程序来完成此操作 但我找不到如何操作或良好的文档 https www selenium dev selenium do
  • hive hadoop 上可用的数据可视化工具

    请推荐一些可以在 Hive Hadoop 上运行的可视化工具 唯一的事情是 它应该接受Hive 这取决于您想要的数据分析和可视化类型 如果您打算使用专有工具 那么Tableau http www tableausoftware com so
  • pyspark没有模块名称错误

    这是我正在遵循的教程中的确切代码 我的同学使用相同的代码没有收到此错误 ImportError Traceback most recent call last
  • 当没有传递参数时如何读取标准输入?

    当我想在没有传递参数 文件 的情况下使用标准输入时 脚本不起作用 有什么方法可以在这段代码中使用标准输入而不是文件吗 我试过这个 if n 1 check if argument exists then 1 stdin if not use
  • 确定函数是否是异步信号安全的(可以在信号处理程序内部调用)

    我的问题是 如果您无权访问函数的实现 是否有办法最终确定函数是否是异步信号安全的 如果没有 有没有办法测试函数是否足够异步信号安全 可以从信号处理程序调用 如果您阅读 signal 或 sigaction 的手册页 您将获得异步信号安全函数
  • 为什么 ContentResolver 看不到其他应用程序添加的文件?

    我将文件添加到Documents MyExcelsFolder通过使用ContentResolver insert然后还将新文件添加到Documents MyExcelsFolder另一个应用程序的文件夹 例如文件管理器 然后我尝试从以下位
  • 平滑地朝目标对象旋转对象

    我想将我的玩家车辆旋转到目标对象方向 侧面 通过下图 我试图以更好的方式解释我的观点 我想将下面的坦克对象旋转到另一个坦克对象 以便它可以指向那个方向 我为此目的编写了这段代码 但它不起作用 IEnumerator DoRotationAt
  • 为什么多行 TextView 中的换行内容会填充父级?

    我将多行文本视图设置为android layout width wrap content 当渲染时 它会占用父级的所有可用宽度 当文本可以容纳在一行中时 wrap content工作正常 但在两行或更多行时 文本视图似乎与父级宽度相匹配 在
  • 在Panorama GUI中找到三个JS坐标?

    我过去玩过一点 ThreeJS 现在正在进行一个新项目 试图在全景中设置热点 我记得使用相机移动车 http davidpaulrosser github io Threejs camera dolly http davidpaulross
  • 为什么我从 Firebase 动态链接 API 收到服务器错误?

    我正在尝试使用 Firebase API 和google api client Ruby gem https github com google google api ruby client 这是我正在使用的代码 配有内联 Gemfile
  • UITextField 中的静态字符前缀

    是否有一种内置方法可以将字符前缀添加到UITextField喜欢下面的截图吗 如果不是 那么实现这一目标的最佳 最直接的方法是什么 我在想background财产也许能够做到这一点 只需添加一个灰色UILabel在上面UITextField
  • 当我的活动依赖于通过 Intent 传递的额外内容时,如何编写 Android JUnit 测试?

    我正在为一个类编写一个 android Junit 测试 该类依赖于通过 Intent 传递给它的额外内容 我能够让该类正常工作 但我仍然想知道如何为这样的类编写单元测试 因为测试仍然失败 public class AddClassEven
  • 如何在 Ruby 中实现进度条?

    我们想要在我们的 Ruby 应用程序之一中实现文件上传进度条 这需要显示上传的确切百分比 然而 尽管我们尽了最大努力 我们还是找不到一种方法来实现完全复制文件上传过程的进度条 您能帮我们解决这个问题吗 如果您使用 Apache 和 Pass
  • 在查询之间引用字段值

    我试图通过使用查询在 Access 中创建计算 目前 一个查询计算 MPP Oil 最大生产潜力 的值 另一个查询需要使用该值来计算 未分配损失 这些计算使用来自基本查询 PEBaseQuery 的公司 资产 年份数据 计算未分配损失的其他
  • T-SQL 语法问题 - 在 CASE 语句中使用 OR

    我想构建一个包含以下逻辑的 CASE 语句 但 sql 编译器不喜欢我的语句中的 OR CASE expression WHEN expression1 OR expression2 THEN
  • IntelliJ IDEA 空构造函数/方法代码风格

    如何调整 Java 的 IntelliJ IDEA 14 代码风格 使其在打开空构造函数 方法后立即保持关闭大括号 E g class A private A public void b Go to 设置 代码风格 Java 换行和大括号并
  • Shiny 允许用户选择要显示的绘图输出

    我有一个闪亮的应用程序 我的服务器功能如下所示 shinyServer function input output session filedata lt reactive infile lt input file1 if is null
  • Visual Studio 代码“获取扩展时出错。XHR 失败”

    This problem started a few weeks ago when I started using NordVPN on my laptop When I try to search for an extension and
  • 首次出现在斯特恩的双原子序列中

    你得到一个整数n 你需要找到它在斯特恩双原子序列中第一次出现的索引 序列定义如下 a 0 0 a 1 1 a 2 i a i a 2 i 1 a i a i 1 See 数学世界 http mathworld wolfram com Ste