之前写过一篇博文:自然数方幂和公式,这次写的目的是因为上次是从数学上完美的解决了这个问题,这次我们要从计算上完美到无法诠释的解决这个问题,当然这归功于我看到的一份sgtlaugh的代码。经过解读体会到其中的奥秘,特此记录。一句话,简直不敢相信。
如果有人说他能在 $O(k)$ 时空复杂度求解 $\sum_{i=1}^n i^k$,你肯定会说这怎么可能别忽悠我了,那我只能说,因为你没看过这篇博文。
$O(k)$ 复杂度 求 $\sum_{i=1}^n i^k$ 其中 $n \leq k$。
我之前一直以为要用 $k \log k$ 的复杂度才能解决这个问题,其实我们只需对所有素数 $p$ 计算 $p^k$ 即可。对于一般的 $i$ 我们先预处理 其最小素因子$sp[i]$。计算 $sp[i]^k \cdot (i/sp[i])^k$ 即可(具体可见最后代码)。由于素数的阶为 $O(\frac{k}{\log k})$ 因此整个复杂度即为 $O(k)$。
由 Lagrange 插值多项式得出最终答案。
因为我们知道 $\sum_{i=1} ^n i^k$ 一定是一个关于$n$的次数为 $k+1$ 的多项式。因此,我们只需计算其在$0,\cdots,k+1$ 上的取值,用 Lagrange 插值多项式即可知道答案。
对于一个次数不超过 $n$ 的多项式 $f(x)$,其在不同位置 $x_0,\cdots,x_n$ 的取值唯一决定了这个多项式:
$$ f(x) = \sum_{i=0} ^n f(x_i) \prod_{j=0,j \neq i} ^n \frac{x-x_j}{x_i - x_j} $$
具体到本问题,我们取 $x=n,nk=k+1,x_i=i$ 那么
$$ f(n) = \sum_{i=0} ^{nk} (-1)^{nk-i} f(x_i) {n \choose i} {n-i-1 \choose nk-i } $$
例题:Codeforces 622F
1 | #include <bits/stdc++.h> |
实际上我们可以不求 $\mod p$ 后的答案,利用大数类得到标准答案,但是这时因为数字实在太大,每次乘法的用时过大,因此仅适合 $k<n$ 的情况
1 | cpp_int f[N]; |
其实如果我们知道最终的上届,求出多个 $\mod p$ 后的答案,再用中国剩余定理貌似很不错。
该方法可以推广成求 $\sum_{i=1}^n f(i)^k$,其中$f(x)$是多项式。具体分析即可。
这种情况一般很难再做到 $O(k)$ 时刻复杂度,而变成了 $O(k \log k) \deg f$ 复杂度,