def calculate(i,j,m,k,n):
for v in range(1,n+1):
ans = (i*k + j) % m
k = ans
return ans
该程序代表一个通用公式,其中x = (i * k + j) % m
其中k
是前一个答案的值。从某种意义上说,它基本上是x1 = (i * x0 + j) % m
和x2 = (i * x1 + j) % m
,依此类推。我遇到的问题是计算大输入需要很长时间。
考虑到这一点,我正在考虑使用算术系列公式,例如:a + (n - 1) * d)
,但我不确定如何在诸如此类的程序中实现它。
答案 0 :(得分:2)
x1 = (i * x0 + j)
x2 = (i * x1 + j) = i * i * x0 + i * j + j
x3 = i * i * i * x0 + i * i * j + i * j + j
xn = i^n * x0 + sum(i^t for t from 0 to n - 1) * j
= i^n * x0 + (i^n - 1) / (i - 1) * j
找到最后一行with Wolfram Alpha。
如果m
是素数,则公式很好。
在这种情况下,您可以执行以prime为模的所有计算,
包括分裂,以保持数字小。
你只需要快速获得取幂i^n
。
我建议你看一下https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method及其中的参考资料。
与循环的O( n )相比,这应该给你O(log( n ))时间复杂度。
如果m
不是素数,则上述公式中的除法很烦人。但是你也可以通过平方计算总和来做类似于求幂的事情。观察
1 + i + i^2 + i^3 + i^4 + i^5 + i^6 + … + i^(2n+1) =
(1 + i) * (1 + i^2 + i^4 + i^6 + … + i^n)
1 + i + i^2 + i^3 + i^4 + i^5 + i^6 + … + i^(2n+2) =
1 + (i + i^2) * (1 + i^2 + i^4 + i^6 + … + i^n)
所以你可以在每一步的右括号中加一半的加数。现在没有除法,因此您可以在每次操作后执行模运算。 因此,您可以定义类似
的内容def modpowsum(a, n, m):
"""(1 + a + a^2 + a^3 + ... + a^n) mod m"""
if n == 0:
return 1
if n == 1:
return (1 + a) % m
if n % 2 == 1:
return ((1 + a) * modpowsum((a * a) % m, (n - 1) // 2, m)) % m
return (1 + ((a + a * a) % m) * modpowsum((a * a) % m, n // 2 - 1, m)) % m
整个计算可以在https://ideone.com/Xh0Fuf运行一些随机和一些不那么随机的测试用例来查看。