【ybt金牌导航8-3-4】【luogu CF622F】K次方求和 / The Sum of the k-th Powers(拉格朗日插值)
K次方求和 / The Sum of the k-th Powers
题目链接:ybt金牌导航8-3-4 / luogu CF622F
题目大意
给你 n,k,要你求 i=1~n 每个 i^k 的和。
思路
首先重新给式子:
\(\sum\limits_{i=1}^ni^k\)
然后这个东西你设成 \(f(n)\),它其实是一个 \(k+1\) 次的多项式。
这里简单的证明一下:
你可以通过差分它得到 \(i^k\),然后接着每次差分就依次变成:
\(i^{k-1},i^{k-2},...\)
最后会变成 \(i^0=1\),即全部都是 \(1\) 的数组。(这个是 \(0\) 次的)
所以反过来就是前缀和,每次次数加一,加到 \(i^k\) 是 \(k\) 次,再前缀就是 \(k+1\) 次了。
然后你就直接用拉格朗日插值,你任意取值就直接取 \(1\sim 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;
}