只要你跑的够快,锅就追不上你

0%

「Codeforces 622F」The Sum of the k-th Powers(多项式)

题目大意

「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
#include <cstdio>
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
}