自然数幂和,有许多种解决方法,其中最典型的有下面几种。
Description
求 ∑ i = 1 n i k \sum_{i=1}^n i^k i=1∑nik
由于答案可能过大,请将其对 1 0 9 + 7 10^9+7 109+7取模。
法1: 暴力
时间复杂度 O ( n log k ) O(n \log k) O(nlogk) 。
法2: 线性筛
不难发现 f ( i ) = i k f(i)=i^k f(i)=ik 是完全积性函数。
于是我们直接线性筛即可。时间复杂度为 O ( n ln n log k + n ) O(\frac {n \ln n} {\log k}+n) O(logknlnn+n) ,类线性。
法3: 高斯消元
可以发现,答案是一个 k + 1 k+1 k+1次多项式,即 ∑ i = 1 n i k = ∑ i = 0 k + 1 f i n i \sum_{i=1}^n i^k=\sum_{i=0}^{k+1} f_i\ n^i i=1∑nik=i=0∑k+1fi ni
现在关键在于如何求出 f i f_i fi。我们可以令 i = 1 , 2 … … k + 2 i=1,2……k+2 i=1,2……k+2,分别得到一组点值,然后高斯消元即可。
最后,我们将多项式的各项系数带入即可求出答案。
法4: 分治
定义函数 f ( n , k ) = ∑ i = 1 n i k f(n,k)=\sum_{i=1}^n i^k f(n,k)=∑i=1nik。
如果
n
n
n为奇数,那么
f
(
n
,
k
)
=
f
(
n
−
1
,
k
)
+
n
k
f(n,k)=f(n-1,k)+n^k
f(n,k)=f(n−1,k)+nk。
如果
n
n
n为偶数,那么
f
(
n
,
k
)
=
f
(
n
2
,
k
)
+
∑
i
=
1
n
2
(
i
+
n
2
)
k
f(n,k)=f(\frac n 2,k)+\sum_{i=1}^{\frac n 2} (i+\frac n 2)^k
f(n,k)=f(2n,k)+i=1∑2n(i+2n)k
令 p = n 2 p=\frac n 2 p=2n,用二项式定理拆开:
f
(
p
,
k
)
+
∑
i
=
1
p
(
i
+
p
)
k
f(p,k)+\sum_{i=1}^{p} (i+p)^k
f(p,k)+∑i=1p(i+p)k
=
f
(
p
,
k
)
+
∑
i
=
1
p
∑
j
=
0
k
i
j
p
k
−
j
C
k
j
=f(p,k)+\sum_{i=1}^p \sum_{j=0}^k i^j p^{k-j}\ C_k^j
=f(p,k)+∑i=1p∑j=0kijpk−j Ckj
=
f
(
p
,
k
)
+
∑
j
=
0
k
C
k
j
p
k
−
j
(
∑
i
=
1
p
i
j
)
=f(p,k)+\sum_{j=0}^k C_{k}^j\ p^{k-j}(\sum_{i=1}^p i^j)
=f(p,k)+∑j=0kCkj pk−j(∑i=1pij)
=
f
(
p
,
k
)
+
∑
j
=
0
k
C
k
j
p
k
−
j
f
(
p
,
j
)
=f(p,k)+\sum_{j=0}^k C_{k}^j\ p^{k-j} f(p,j)
=f(p,k)+∑j=0kCkj pk−jf(p,j)
于是我们直接记忆化搜索处理即可。
由于递归共有 k k k层,每一层递归了 log k \log k logk次,且每次求和的复杂度为 k k k,所以总复杂度为 O ( k 2 log k ) O(k^2 \log k) O(k2logk)。
法5: 递推
首先,不难发现 ∑ i = 1 n ( i + 1 ) k − i k = ( n + 1 ) k − 1 \sum_{i=1}^n (i+1)^k-i^k=(n+1)^k-1 i=1∑n(i+1)k−ik=(n+1)k−1
同时,也有 ∑ i = 1 n ( i + 1 ) k − i k \sum_{i=1}^n (i+1)^k-i^k i=1∑n(i+1)k−ik
= ∑ i = 1 n ( ∑ j = 0 k i j C k j ) − i k =\sum_{i=1}^n (\sum_{j=0}^k i^j\ C_k^j)-i^k =i=1∑n(j=0∑kij Ckj)−ik
= ∑ i = 1 n ( ∑ j = 0 k − 1 i j C k j ) =\sum_{i=1}^n (\sum_{j=0}^{k-1} i^j\ C_k^j) =i=1∑n(j=0∑k−1ij Ckj)
= ∑ j = 0 k − 1 ( ∑ i = 1 n i j ) C k j =\sum_{j=0}^{k-1}(\sum_{i=1}^n i^j) C_k^j =j=0∑k−1(i=1∑nij)Ckj
= ∑ j = 0 k − 1 f ( n , j ) C k j =\sum_{j=0}^{k-1} f(n,j) C_k^j =j=0∑k−1f(n,j)Ckj
所以,我们得到了 ( n + 1 ) k − 1 = ∑ j = 0 k − 1 f ( n , j ) C k j (n+1)^k-1=\sum_{j=0}^{k-1} f(n,j)\ C_k^j (n+1)k−1=j=0∑k−1f(n,j) Ckj
( n + 1 ) k − 1 = ( ∑ j = 0 k − 2 f ( n , j ) C k j ) + f ( n , k − 1 ) C k k − 1 (n+1)^k-1=(\sum_{j=0}^{k-2} f(n,j)\ C_k^j)+f(n,k-1)\ C_{k}^{k-1} (n+1)k−1=(j=0∑k−2f(n,j) Ckj)+f(n,k−1) Ckk−1
( n + 1 ) k − 1 = ( ∑ j = 0 k − 2 f ( n , j ) C k j ) + k f ( n , k − 1 ) (n+1)^k-1=(\sum_{j=0}^{k-2} f(n,j)\ C_k^j)+k f(n,k-1) (n+1)k−1=(j=0∑k−2f(n,j) Ckj)+kf(n,k−1)
最终,我们得到了递推式
f ( n , k ) = ( n + 1 ) k + 1 − 1 − ∑ i = 0 k − 1 f ( n , i ) C k + 1 i k + 1 f(n,k)=\frac {(n+1)^{k+1}-1-\sum_{i=0}^{k-1} f(n,i)\ C_{k+1}^i} {k+1} f(n,k)=k+1(n+1)k+1−1−∑i=0k−1f(n,i) Ck+1i
时间复杂度为 O ( k 2 ) O(k^2) O(k2)。
法6: 拉格朗日插值
首先回忆一下法 1 1 1的做法。我们求出了多项式的 k + 2 k+2 k+2个点值,然后高斯消元求出 k + 1 k+1 k+1次多项式的各项系数,最后再带入 x = n x=n x=n求出答案……
不难发现这个问题形如“给定 k + 2 k+2 k+2个点值 f ( x 1 ) , f ( x 2 ) ⋯ f ( x k + 2 ) f(x_1),f(x_2) \cdots f(x_{k+2}) f(x1),f(x2)⋯f(xk+2),请求出 f ( n ) f(n) f(n)”。我们考虑用拉格朗日插值替代掉时间复杂度较差的高斯消元。
我们直接暴力插值,时间复杂度 O ( k 2 ) O(k^2) O(k2)的。
观察一下拉格朗日差值的式子: f ( n ) = ∑ i = 1 k + 2 y i ∏ j ≠ i n − x j x i − x j f(n)=\sum_{i=1}^{k+2} y_i \prod_{j \neq i} \frac {n-x_j} {x_i-x_j} f(n)=∑i=1k+2yi∏j=ixi−xjn−xj。
不难发现,本题中带入的点值没有特殊要求,于是我们可以构造一组特殊的点值并将它们带进去来优化复杂度。傅里叶: 把单位根带进去
最优方案是带入一组 x x x连续的点值,即将 x = 1 , 2 ⋯ k + 2 x=1,2 \cdots {k+2} x=1,2⋯k+2依次带入。此时后面的式子就变成了
∑ i = 1 k + 2 y i ∏ j ≠ i n − j i − j \sum_{i=1}^{k+2} y_i \prod_{j \neq i} \frac {n-j} {i-j} i=1∑k+2yij=i∏i−jn−j
不难发现, ∏ j ≠ i n − j i − j \prod_{j \neq i} \frac {n-j} {i-j} ∏j=ii−jn−j是一个前缀积/后缀积的形式,我们可以预处理。
通过一些逆元的小 Trick 可以将时间复杂度优化到 O ( k ) O(k) O(k)。
法7: 生成函数
Part 1: n 固定 , k 不固定
令 f k ( n ) = ∑ i = 0 n i k f_k(n)=\sum_{i=0}^n i^k fk(n)=∑i=0nik ,我们构造 EGF 如下:
F n ( x ) = ∑ i = 0 n S i ( n ) x i i ! F_n(x)=\sum_{i=0}^n S_i(n) \frac {x^i} {i!} Fn(x)=i=0∑nSi(n)i!xi
展开一波,
F k ( x ) = ∑ i = 0 n ∑ j = 1 n j i x i i ! F_k(x)=\sum_{i=0}^{n} \sum_{j=1}^n j^i \frac {x^i} {i!} Fk(x)=i=0∑nj=1∑njii!xi
F k ( x ) = ∑ j = 1 n ∑ i = 0 n j i x i i ! F_k(x)=\sum_{j=1}^{n} \sum_{i=0}^{n} j^i \frac {x^i} {i!} Fk(x)=j=1∑ni=0∑njii!xi
F k ( x ) = ∑ j = 1 n e j x F_k(x)=\sum_{j=1}^{n} e^{jx} Fk(x)=j=1∑nejx
不难发现右边是一个等比数列求和的形式,则
F k ( x ) = e n x − 1 1 − e − x F_k(x)=\frac {e^{nx}-1} {1-e^{-x}} Fk(x)=1−e−xenx−1
写成更加恐怖的形式:
∑ i = 0 n i n x i i ! − 1 1 − ∑ i = 0 n ( − x ) i i ! \huge {\frac {\sum_{i=0}^{n} i^n \frac {x^i} {i!} \ -1} {1-\sum_{i=0}^{n} \frac {(-x)^i} {i!}}} 1−∑i=0ni!(−x)i∑i=0nini!xi −1
于是,我们通过多项式求逆预处理,每次询问即可 O ( 1 ) O(1) O(1) 查询。
Part 2: n 不固定, k 固定
令第 i i i 个伯努利数为 B i B_i Bi ,其 EGF 为 F ( x ) F(x) F(x) 。直接上两个套路式:
F ( x ) = x e x e x − 1 F(x)=\frac {xe^x} {e^x-1} F(x)=ex−1xex
∑ i = 1 n i k = 1 k + 1 ∑ i = 1 k + 1 C k + 1 i B k − i + 1 n i \sum_{i=1}^n i^k=\frac 1 {k+1} \sum_{i=1}^{k+1} C_{k+1}^i B_{k-i+1} n^i i=1∑nik=k+11i=1∑k+1Ck+1iBk−i+1ni
此时,我们直接多项式多点求值即可求出所有的答案。令询问次数为 q q q ,那么时间复杂度 O ( q log 2 q + k log k ) O(q \log^2 q + k \log k) O(qlog2q+klogk) 。
在实现的时候,多点求值递归到一个较小的区间后,直接暴力求值可以大幅减小常数。同时,注意使用较快的多项式板子,以免被毒瘤出题人卡常。
Summary
这 7 7 7 个方法循序渐进,时间复杂度从较差到较优,实现从容易到复杂。
在考场上,建议使用在时间复杂度正确的情况下选择最好写的做法。