Algorithm 用Python计算模为m的巨大斐波那契数
这个问题的目标是计算F[n]mod m。这里的输入是n和m,其中n表示斐波那契数的指数,比如F[0]=0,F[1]=1,F[2]=1,F[3]=2,m表示将被除以的数。制约因素包括:Algorithm 用Python计算模为m的巨大斐波那契数,algorithm,python-2.7,fibonacci,Algorithm,Python 2.7,Fibonacci,这个问题的目标是计算F[n]mod m。这里的输入是n和m,其中n表示斐波那契数的指数,比如F[0]=0,F[1]=1,F[2]=1,F[3]=2,m表示将被除以的数。制约因素包括: n>=1和n=2以及m=1和n=2和m我不明白您在查找维护程序(m)中试图做什么,或者为什么需要它。您已经在使用Fibonacci by double算法,它类似于(并且通常是从)矩阵平方求幂算法。通过在每一步修改部分结果,可以修改求幂运算以有效地处理模幂运算 def fibmod(n, m): asse
- n>=1和n=2以及m=1和n=2和m我不明白您在
中试图做什么,或者为什么需要它。您已经在使用Fibonacci by double算法,它类似于(并且通常是从)矩阵平方求幂算法。通过在每一步修改部分结果,可以修改求幂运算以有效地处理模幂运算查找维护程序(m)
def fibmod(n, m): assert 1 <= n <= 10**18, n assert 2 <= m <= 10**5, m def f(n): if n == 0: return 0, 1 else: a, b = f(n // 2) c = a * (2*b - a) % m d = (a**2 + b**2) % m if n % 2 == 0: return c, d else: return d, (c + d) % m return f(n)[0]
def fibmod(n,m):
assert 1通过使用模幂运算,可以非常快速地完成此操作 考虑以下矩阵乘法:
如果| 0 1 | | a | | b | | | x | | = | | | 1 1 | | b | | a+b |
和a
是最后两项,那么您应该马上看到,此乘法的结果是斐波那契序列的下一次迭代。要获得执行此乘法b
n次的结果,需要计算2x2矩阵
(mod m)的(0,1;1,1)
幂。这可以通过将该矩阵提升到2的连续幂来快速完成 例如,要计算此矩阵的第10次方:n次
将矩阵平方三次后,我们现在得到了| 0 1 | | 0 1 | | 1 1 | A x A = A**2 = | | x | | = | | | 1 1 | | 1 1 | | 1 2 | | 1 1 | | 1 1 | | 2 3 | A**4 = (A**2)**2 = | | x | | = | | | 1 2 | | 1 2 | | 3 5 | | 2 3 | | 2 3 | | 13 21 | A**8 = (A**4)**2 = | | x | | = | | | 3 5 | | 3 5 | | 21 34 |
和A**8
的值。将这些值相乘,得到A**2
:A**10
在常规算术中,这些数字将迅速变得巨大,但如果您以m为模执行所有乘法,则这不是问题。最后,将向量(0;1)乘以得到的矩阵,得到您的答案(或者,等效地,只需选择矩阵顶行中的第二个数字) 所需的乘法次数约为| 13 21 | | 1 1 | | 34 55 | A**10 = | | x | | = | | | 21 34 | | 1 2 | | 55 89 |
,因此所需的时间应该非常小,即使log(n)
为万亿或更多m
为什么这个问题陈述看起来如此熟悉?;-)竞争编程高手对此非常熟悉:这是www.spoj.com的FIB64问题。在g++8.3.0版(符合C++14)的英特尔G860 CPU arch=skylake上,在不到2秒钟的时间内要解决500000个fib(n)%m个测试用例n和m的大小为64位,即10^18。在英特尔上g++中长整型溢出的限制下,这对于模块化数学实现是一个很好的挑战。在Python中,溢出不是问题,但是Python在运行时500000次的速度太慢了。我的实现是在C++中,我用500000个快速的加倍时间来运行所有的这两个测试用例,但是我使用C++技巧来避免溢出,而不实现一个远远超出问题的目标的BigTigBand库。NB:对于Myz的外部库,禁止使用C++,甚至GMPY2禁止Python另一个注释:对于n=10 ^ 15,您的术语记忆以查找FIB(n)%m的周期不是一个好主意,因为N很大。关于这个数学问题,SPOJ还有另一个问题:它与米歇尔·雷诺(Michel Renault)的一个数学博士有关,用C++实现这个问题并不容易。在www.SPOJ.com上,关于斐波那契周期的问题名为PISANOfast Double,比模幂更快。请看我对findReminders尝试的记忆想法的评论。这种模式是存在的,但它涉及的数学远远超出了我们许多人的知识。论文脚本中的数学部分不完整,无法直接实现。| 13 21 | | 1 1 | | 34 55 | A**10 = | | x | | = | | | 21 34 | | 1 2 | | 55 89 |