K次方求和 / The Sum of the k-th Powers
题目链接:ybt金牌导航8-3-4 / luogu CF622F
题目大意
给你 n,k,要你求 i=1~n 每个 i^k 的和。
思路
首先重新给式子:
∑
i
=
1
n
i
k
\sum\limits_{i=1}^ni^k
i=1∑nik
然后这个东西你设成 f ( n ) f(n) f(n),它其实是一个 k + 1 k+1 k+1 次的多项式。
这里简单的证明一下:
你可以通过差分它得到
i
k
i^k
ik,然后接着每次差分就依次变成:
i
k
−
1
,
i
k
−
2
,
.
.
.
i^{k-1},i^{k-2},...
ik−1,ik−2,...
最后会变成
i
0
=
1
i^0=1
i0=1,即全部都是
1
1
1 的数组。(这个是
0
0
0 次的)
所以反过来就是前缀和,每次次数加一,加到
i
k
i^k
ik 是
k
k
k 次,再前缀就是
k
+
1
k+1
k+1 次了。
然后你就直接用拉格朗日插值,你任意取值就直接取 1 ∼ k + 2 1\sim k+2 1∼k+2 的值,然后用连续的那种搞可以了。
代码
#include<cstdio>
#define ll long long
#define mo 1000000007
using namespace std;
ll n, k, y[1000003], jc[1000003];
ll ans, now, pre[1000003], suf[1000003];
ll ksm(ll x, ll y) {
ll re = 1;
while (y) {
if (y & 1) re = re * x % mo;
x = x * x % mo;
y >>= 1;
}
return re;
}
ll work(int k, int n) {
pre[0] = 1;
for (int i = 1; i <= n; i++)
pre[i] = pre[i - 1] * (k - i + mo) % mo;
suf[n + 1] = 1;
for (int i = n; i >= 1; i--)
suf[i] = suf[i + 1] * (k - i + mo) % mo;
jc[0] = 1;
for (int i = 1; i <= n; i++) jc[i] = jc[i - 1] * i % mo;
ll ans = 0;
for (int i = 1; i <= n; i++) {
ans = (ans + y[i] * pre[i - 1] % mo * suf[i + 1] % mo * ksm(jc[i - 1] * jc[n - i] % mo * (((n - i) & 1) ? mo - 1 : 1) % mo, mo - 2) % mo) % mo;
}
return ans;
}
int main() {
scanf("%lld %lld", &n, &k);
for (int i = 1; i <= k + 2; i++) {
now = (now + ksm(i, k)) % mo;
y[i] = now;
}
printf("%lld", work(n, k + 2));
return 0;
}