有没有算法可以计算 (1^x + 2^x + 3^x + ... + n^x) mod 1000000007
?
注意:这里的a^b
表示a的b次方。
限制条件为1 <= n <= 10^16, 1 <= x <= 1000
,因此N的值非常大。
如果m = 1000000007
,我只能解决O(m log m)
的问题。但是由于时间限制为2秒,速度非常慢。
你有任何有效的算法吗?
有评论说这可能是这个问题的重复,但它肯定是不同的。
有没有算法可以计算 (1^x + 2^x + 3^x + ... + n^x) mod 1000000007
?
注意:这里的a^b
表示a的b次方。
限制条件为1 <= n <= 10^16, 1 <= x <= 1000
,因此N的值非常大。
如果m = 1000000007
,我只能解决O(m log m)
的问题。但是由于时间限制为2秒,速度非常慢。
你有任何有效的算法吗?
有评论说这可能是这个问题的重复,但它肯定是不同的。
你可以总结这个系列。
1**X + 2**X + ... + N**X
利用Faulhaber公式,可以得到一个具有X + 1
次幂的多项式来计算任意的N
。
如果您不想计算Bernoulli数,可以通过解决X + 2
个线性方程(对于N = 1、N = 2、N = 3、...、N = X + 2
)来找到这个多项式,虽然这种方法比较慢,但更容易实现。
让我们举一个X = 2
的例子。在这种情况下,我们有一个X + 1 = 3
阶多项式:
A*N**3 + B*N**2 + C*N + D
线性方程为:
A + B + C + D = 1 = 1
A*8 + B*4 + C*2 + D = 1 + 4 = 5
A*27 + B*9 + C*3 + D = 1 + 4 + 9 = 14
A*64 + B*16 + C*4 + D = 1 + 4 + 9 + 16 = 30
解决方程后,我们将得到
A = 1/3
B = 1/2
C = 1/6
D = 0
最终公式为
1**2 + 2**2 + ... + N**2 == N**3 / 3 + N**2 / 2 + N / 6
现在,您需要做的就是将一个任意大的N
放入公式中。到目前为止,该算法的复杂度为O(X**2)
(因为它不依赖于N
)。
有几种加速模幂运算的方法。从现在开始,我将使用**
代表"求幂",%
代表"取余"。
首先,我们有一些观察结果。对于任意的a、b和m,恒有 (a * b) % m
等于((a % m) * (b % m)) % m
。同时,恒有a ** n
等于(a ** floor(n / 2)) * (a ** (n - floor(n/2)))
。这意味着,对于一个小于等于1000的指数,我们可以通过最多20次乘法(和21次取模)完成幂运算。
我们也可以跳过许多计算,因为(a ** b) % m
等于((a % m) ** b) % m
,如果m明显小于n,则我们只需要多次重复求和,并在末尾截取部分重复即可。
1000000006
同余于 -1
,所以 1^x
和 1000000006^x
相互抵消,其他很多项也是如此。但是如果 x 是偶数,我没有看到任何捷径。 - Tom Zych500000003 ** x
%m;乘以floor(n / m)
;循环从1到n%m,进行指数运算和求和”。 - Vatine我认为Vatine的答案可能是正确的方法,但我已经打出了这个答案,对于这个问题或其他类似的问题可能会有用。
今天早上我没有时间提供详细的答案,但请考虑以下内容。计算1^2 + 2^2 + 3^2 + ... + n^2
需要O(n)步。然而,它等同于(n(n+1)(2n+1)/6)
,可以在O(1)时间内计算出来。对于任何更高的整数幂x,都存在类似的等价关系。
可能存在一般性的解决方案;我不知道有没有,Wolfram Alpha似乎也不知道。然而,通常等价表达式的次数为x+1,可以通过计算一些示例值并解决一组线性方程来计算系数。
但是,对于像你的问题中的1000这样大的x,这将是困难的,并且可能无法在2秒钟内完成。
也许比我更懂数学的人可以将其转化为可行的解决方案?
编辑:糟糕,我看到Fabian Pijcke在我发帖之前已经发布了一个关于Faulhaber's formula的有用链接。
Function Sum(x: Number, n: Integer) -> Number
P := PolySum(:x, n)
return P(x)
End
Function PolySum(x: Variable, n: Integer) -> Polynomial
C := Sum-Coefficients(n)
P := 0
For i from 1 to n + 1
P += C[i] * x^i
End
return P
End
Function Sum-Coefficients(n: Integer) -> Vector of Rationals
A := Create-Matrix(n)
R := Reduced-Row-Echelon-Form(A)
return last column of R
End
Function Create-Matrix(n: Integer) -> Matrix of Integers
A := New (n + 1) x (n + 2) Matrix of Integers
Fill A with 0s
Fill first row of A with 1s
For i from 2 to n + 1
For j from i to n + 1
A[i, j] := A[i-1, j] * (j - i + 2)
End
A[i, n+2] := A[i, n]
End
A[n+1, n+2] := A[n, n+2]
return A
End
我们的目标是获得一个多项式 Q
,使得 Q(x) = sum i^n for i from 1 to x
。已知 Q(x) = Q(x - 1) + x^n
=> Q(x) - Q(x - 1) = x^n
,因此我们可以像下面这样建立一个方程组:
d^0/dx^0( Q(x) - Q(x - 1) ) = d^0/dx^0( x^n )
d^1/dx^1( Q(x) - Q(x - 1) ) = d^1/dx^1( x^n )
d^2/dx^2( Q(x) - Q(x - 1) ) = d^2/dx^2( x^n )
... .
d^n/dx^n( Q(x) - Q(x - 1) ) = d^n/dx^n( x^n )
Q(x) = a_1*x + a_2*x^2 + ... + a_(n+1)*x^(n+1)
,我们将会有 n+1
个线性方程,未知数为 a1, ..., a_(n+1)
,而且系数 cj
乘以方程 i
中的未知数 aj
遵循以下模式(其中 (k)_p
= (k!)/(k - p)!
):
j < i
,则 cj
= 0
cj
= (j)_(i - 1)
i
个方程的独立值为 (n)_(i - 1)
。解释起来有点麻烦,但你可以在 这里 查看证明。
上述算法等同于解决这个线性方程组。在https://github.com/fcard/PolySum中可以找到大量的实现和进一步的解释。这个算法的主要缺点是它消耗了很多内存,即使我最节省内存的版本在n=3000
时也使用了几乎1gb
的内存。但它比SymPy和Mathematica都要快,所以我认为这没问题。与Schultz's method相比,后者使用了一组备选方程。
对于小的n
,手动应用这种方法很容易。当n=1
时,矩阵如下:
| (1)_0 (2)_0 (1)_0 | | 1 1 1 |
| 0 (2)_1 (1)_1 | = | 0 2 1 |
应用高斯-约旦消元法,我们得到
| 1 0 1/2 |
| 0 1 1/2 |
结果 = {a1 = 1/2, a2 = 1/2}
=> Q(x) = x/2 + (x^2)/2
请注意,矩阵总是已经处于行阶梯形式,我们只需要将其简化。
对于 n=2
:
| (1)_0 (2)_0 (3)_0 (2)_0 | | 1 1 1 1 |
| 0 (2)_1 (3)_1 (2)_1 | = | 0 2 3 2 |
| 0 0 (3)_2 (2)_2 | | 0 0 6 2 |
应用高斯-约旦消元法,我们得到
| 1 1 0 2/3 | | 1 0 0 1/6 |
| 0 2 0 1 | => | 0 1 0 1/2 |
| 0 0 1 1/3 | | 0 0 1 1/3 |
结果 = {a1 = 1/6, a2 = 1/2, a3 = 1/3}
=> Q(x) = x/6 + (x^2)/2 + (x^3)/3
该算法速度的关键在于它不会为矩阵的每个元素计算阶乘,而是知道 (k)_p
= (k)_(p-1) * (k - (p - 1))
,因此 A[i,j]
= (j)_(i-1)
= (j)_(i-2) * (j - (i - 2))
= A[i-1, j] * (j - (i - 2))
,所以它使用上一行来计算当前行。
n
,您可以在合理的时间内直接计算总和。对于大的n
,我认为您可以找到这样的数字对,它们相加等于 1000000007(例如 1 和 1000000006,7 和 1000000000...)。这些数字分别等于 1 和(-1)mod 1000000007,因此它们在求和中被抵消 - 同样,它们各自的幂也会被抵消。然后您可以跳过它们,这样您只需直接计算不超过 1000000007 个总和项即可... - CiaPan