题目大意
「Codeforces 622F」The Sum of the k-th Powers
求 $\sum_{i = 1}^{n} i^k \bmod 10^9 + 7$。
数据范围:$n \le 10^9, k \le 10^6$。
思路分析
直接做显然是不行的,我们猜想 $\sum_{i = 1}^{n} i^k$ 是一个 $k + 2$ 次多项式。我们先对于 $1 \le i \le k + 2$ 计算出 $a_i = \sum_{j = 1}^{i} j^k$ 的值,然后使用拉格朗日插值来求出该多项式在 $n$ 处的值即可。然而拉格朗日插值的复杂度是 $O(k^2)$ 的,不能通过此题。
考虑拉格朗日插值的过程。根据拉格朗日插值公式,答案为:
而我们有:
所以我们只需要预处理阶乘即可计算答案了。由于一开始的 $k$ 次方和计算和计算答案时需要求逆元,时间复杂度为 $O(k \log k)$。
能不能线性呢?答案是肯定的。注意到 $\text{ID}_k(x)$ 是完全积性函数,我们可以使用线性筛在 $O(k + \frac{k \log k}{\ln k}) = O(k)$ 的时间内算出它的前缀和。对于逆元,我们只需要使用线性求逆元的科技即可。这样,时间复杂度就优化成了 $O(k)$。
代码实现
1 |
|
2 | |
3 | const int maxn = 1e6, mod = 1e9 + 7; |
4 | int n, k, m, p[maxn + 3], f[maxn + 3], fact[maxn + 3], finv[maxn + 3]; |
5 | int num[maxn + 3], suf[maxn + 3], inv[maxn + 3]; |
6 | bool b[maxn + 3]; |
7 | |
8 | int func(int x) { |
9 | return x < 0 ? x + mod : x < mod ? x : x - mod; |
10 | } |
11 | |
12 | int qpow(int a, int b) { |
13 | int c = 1; |
14 | for (; b; b >>= 1, a = 1ll * a * a % mod) { |
15 | if (b & 1) c = 1ll * a * c % mod; |
16 | } |
17 | return c; |
18 | } |
19 | |
20 | void prework(int n) { |
21 | f[1] = 1; |
22 | for (int i = 2; i <= n; i++) { |
23 | if (!b[i]) { |
24 | f[i] = qpow(i, k); |
25 | p[++m] = i; |
26 | } |
27 | for (int j = 1; j <= m && i * p[j] <= n; j++) { |
28 | b[i * p[j]] = true; |
29 | f[i * p[j]] = 1ll * f[i] * f[p[j]] % mod; |
30 | if (!i % p[j]) { |
31 | break; |
32 | } |
33 | } |
34 | } |
35 | for (int i = 1; i <= n; i++) { |
36 | f[i] += f[i - 1]; |
37 | f[i] < mod ? 0 : f[i] -= mod; |
38 | } |
39 | fact[0] = 1; |
40 | for (int i = 1; i <= n; i++) { |
41 | fact[i] = 1ll * fact[i - 1] * i % mod; |
42 | } |
43 | finv[n] = qpow(fact[n], mod - 2); |
44 | for (int i = n; i; i--) { |
45 | finv[i - 1] = 1ll * finv[i] * i % mod; |
46 | } |
47 | } |
48 | |
49 | void solve(int pre[], int inv[], int n) { |
50 | pre[0] = pre[n + 1] = 1; |
51 | for (int i = 0; i <= n + 1; i++) { |
52 | suf[i] = pre[i]; |
53 | } |
54 | for (int i = 1; i <= n; i++) { |
55 | pre[i] = 1ll * pre[i - 1] * pre[i] % mod; |
56 | } |
57 | for (int i = n; i; i--) { |
58 | suf[i] = 1ll * suf[i + 1] * suf[i] % mod; |
59 | } |
60 | int x = qpow(pre[n], mod - 2); |
61 | for (int i = 1; i <= n; i++) { |
62 | inv[i] = 1ll * x * pre[i - 1] % mod * suf[i + 1] % mod; |
63 | } |
64 | } |
65 | |
66 | int main() { |
67 | scanf("%d %d", &n, &k); |
68 | prework(k + 2); |
69 | if (n <= k + 2) { |
70 | printf("%d\n", f[n]); |
71 | return 0; |
72 | } |
73 | for (int i = 1; i <= k + 2; i++) { |
74 | num[i] = n - i; |
75 | } |
76 | solve(num, inv, k + 2); |
77 | int ans = 0; |
78 | for (int i = 1; i <= k + 2; i++) { |
79 | int x = 1ll * f[i] * inv[i] % mod; |
80 | x = 1ll * x * finv[i - 1] % mod * finv[k + 2 - i] % mod; |
81 | if ((k + 2 - i) & 1) x = func(-x); |
82 | ans = func(ans + x); |
83 | } |
84 | for (int i = 1; i <= k + 2; i++) { |
85 | ans = 1ll * ans * (n - i) % mod; |
86 | } |
87 | printf("%d\n", ans); |
88 | return 0; |
89 | } |