如何有效地找到数字和序列的元素?


20

出于兴趣,我试图解决Euler项目(数字总和序列)的“最近”类别中的问题 。但是我想不出一种有效解决问题的方法。问题如下(在最初的问题序列中,开始时有两个问题,但不会改变序列):

的数字和序列是1,2,4,8,16,23,28,38,49 ....其中nth序列的术语是和数字序列中它前面。找到序列的1015th项。

天真的解决方案无法实现,因为它需要大量时间。我试图减少的问题,以矩阵幂的情况下(这将花费O(log(1015))的时间量),但不能想出这样的复发拟合线性标准作为复发,这种序列是相当特有。可以看出,该序列由重复控制:

an=an1+d(an1).....(1)

其中annth序列的术语和d是给定的自然数作为数(例如数字输入返回总和时的功能。d(786)=21)。我的第二种方法是尝试在序列中找到某种模式。可以看出,序列的前几项可以写成

   a_1 = 1  
   a_2 = 1 + d( 1 )
   a_3 = 1 + d( 1 ) + d( 1 + d( 1 ) )
   a_4 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) )
   a_5 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) + d( 1 +  d(  
   1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) )

从上面的模式可以看出,可以通过以下方法生成序列的nth项:

  1. 写出2n1 1,并在其间加上符号。
  2. 保留第一个,然后 在接下来的2 0项上应用函数d,然后在接下来的2 1项上应用函数d,然后在接下来的2 2项上应用函数d,依此类推。1d202122
  3. 然后将上述方法递归应用于所应用的每个函数的参数。d

例如,如果n = 3,我们执行以下操作:

    1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
    1 + d( 1 ) + d( 1 + 1 ) + d( 1 + 1 + 1 + 1 )
    1 + d( 1 ) + d( 1 + d(1) ) + d( 1 + d( 1 ) + d( 1 +d( 1 ) ) )

通过动态编程,我可以使用上述方法在时间O l o g 2 10 15)中生成项,这再次没有天真的解决方案好。nthO(log(21015))

编辑1
可以观察到的另一件事是。例如d a 6= d 23 = d 32 = 5。但是我无法利用这一点。我再次尝试找到线性递归关系(用于矩阵求幂),但是我找不到它。d(an)=d(2n1)d(a6)=d(23)=d(32)=5

编辑2

下图是在较小范围内绘制序列时的图表(绘制了序列的前项)。 106在此处输入图片说明

PS:我知道不建议向Euler项目寻求解决方案。但是我只想一个新的方向或暗示,因为我过去几天一直在圈子里移动。如果那也不可接受,那么我可以在建议的情况下删除问题。


1
我觉得You are given a106 = 31054319.在原始的Euler问题中是一个提示。
Filip Haglund

@FilipHaglund不是提示。仅凭蛮力,我就可以轻松计算出该值。它仅用于检查您的方法。
sashas '16

3
也在OEIS上:oeis.org/A004207
Yuval Filmus

@EvilJS可以,我将图形绘制成一个扩展,它以之字形逐渐增加。您能否详细说明最后一点“缓存模式..”
sashas 2016年

给定有趣的模式出现在mod 9中,如果我们看一下mod 11或mod 99序列,会发生什么有趣的事情吗?可以从奇数索引的数字之和和偶数索引的数字之和得出值mod 11。可以从相邻数字对的总和中得出值mod 99。
DW

Answers:


4

您的序列在oeis.org/A004207中描述为数字总和。有样序列模9一些好点已经重复图案,这股与数字根oeis.org/A065075oeis.org/A001370。如果这些性质是有用的,则是开放问题(因为对于 n - t h数,没有封闭形式的方程式)。(1,2,4,8,7,5)nth

此序列的一些属性值得一提:
当计算数时,您只需要存储计数器(以知道计数器是哪个数字)和数字本身即可。重新启动时,不需要任何其他操作,因为下一个数字是当前数字+其数字的总和。nth

首先采取一些步骤来确保速度,将数字放入数组中是很好的,避免了朴素的mod和div计算,这很昂贵。这可以使速度不断提高,但有时确实很重要。

从起点开始,您可以计算下一个和下一个,它可以计算到某个点,这一点就是位数的变化。
更重要的是,模式随着数量的增加而变化。
与数字本身相比,数字总和很小,因此在大多数操作中仅数字部分会发生变化。
那么我们到底可以缓存什么呢?

我们知道,对于具有相同数字总和的两个数字,获得下一个数字的加法将是相同的。那下一个呢?

萨沙

剧透警报,下面是非常明确的缓存模式

它取决于其他条件,例如运行中不会改变的数字,我称其为shift,起始金额为start

进行一些任意运行,例如,并从09开始,我们可以缓存从起点到100的每个模式10009100,对元素数量进行计数(以知道如何处理计数器,这需要给定号),并记住它。 nth

好。到目前为止,涵盖任何起点,超过会有什么变化? 不幸的是,这种模式无法正常工作,因为如果您尝试100
决策开始等于 1,下一个数字是完全计算的,但第二个休息。 1001

在这里,我们必须覆盖shift设置为开始设置为0。这也意味着计算不同班次的表格。 10

我们真的需要计算所有这些吗?不是,不是
表的一部分只是另一个开始项。
例如,从开始给出了相同的序列移位。 那么,我们需要计算更长的缓存吗? 不,我们将其计算出来以转移更改以获取另一次运行,因此它将节省大量内存。 1,2,4,8

现在,当表格被覆盖时,我们从初始设置开始,从表格中选择总和,添加计数器,然后看到:从101,更新变量并跳转到218,重复步骤305- > 406- > 517- > 607 -> 719- > 805- > 904- > 1003。 好。现在怎么办? 11012183054065176077198059041003

我们可以继续,直到移位高于计算得出。
进一步讲,我们可能会即时构建更多的运行,预先计算更大的运行或观察其他模式(例如我们可以局部重用已计算的表)。
看看不同100,1000,10000,100000,1000000...
100


4

由于您要求输入“新的方向或提示”,而我不知道答案,因此我将其保留在此处,希望对您有所帮助。一些想法:

很有可能会有模式mod 9,因为

k>1,kZ10k1mod9

您可以通过归纳证明。

这意味着所有数字都等于其数字mod 9的总和。

此外, an=d(an)mod9

an=an1+d(an1)=2d(an1)mod9

如果我们继续扩大这种复发率,我们得到

an=2nmod9

解释了模式mod 9。

an=9k+2n

这里的代码比一般代码少:

import matplotlib.pyplot as plt
import numpy as np

#sum digits of n
def sum_digits(n):
    s = 0
    while n:
        s += n % 10
        n //= 10
    return s

#get the sequence to n digits
def calculate(n):
    retval = [1]
    for i in range(n):
        retval.append(retval[-1] + sum_digits(retval[-1]))
    return retval;

#empirically confirm that a_n = 2^n mod 9
def confirmPow2(a):
    count = 0
    for i in a[:10000]:
        if((i%9) != (2**count % 9)):
            print "false"
        count = count + 1

#find gaps divisible by 9 in a subset of a
def find9Gaps(a):
    count = 0
    S = []
    for i in a[:10000]:
         S.append(((2**count ) - i)/9)
         count = count + 1
    return S

#repeatedly sum the digits until they're less than 9...
#gives some interesting patterns
def repeatedDigitSum():
    for i in range(1000, 1100):
         print "=========for ",i
         while i > 9:
                 i = sum_digits(i)
                 print i 


a = calculate(10**6)
b = find9Gaps(a)
plt.plot(range(len(b[:100])), b[:100])
plt.show()

该图(前100个)看起来是指数级的,但我认为这并不完美。

缝隙

这是输出

>>> plt.plot(range(len(b[5:60])), np.log2(np.array(b[5:60])))
>>> plt.show()

logarithmic plot of the gaps

我的最后一件事是,如果您将一个数字的数字相加,然后将结果数字的数字相加,然后重复一次,您最终会得到该数字mod 9。

鉴于上述有关10 mod 9的幂的事实是有道理的。

nd(n)d(d(n))mod9

它给出了一个有趣的数字序列。

编辑:显然,这称为“数字根”。


1
它至少被评论了三遍。另外,当您绘制看起来像指数的图形时,也许您应该使用对数,在比例轴上告知它?如果您绘制了可读的10 ^ 16项,我会真的印象深刻。
Evil

评论了3次是什么?人们说这里有一个“ pattern mod 9”,但我感觉还不清楚那是什么。我只是做了一些探索,并评论了我所拥有的,因为我认为我将无法继续从事这一工作。同样,我没有解决方案,但问题并没有提出解决方案。
quietContest

根据EvilJS的建议添加了对数图,不能绘制更大的图,因为numpy中断,我真的没有时间继续追求这个问题
quietContest
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.