【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;
}
posted @ 2021-12-08 17:13  あおいSakura  阅读(34)  评论(0编辑  收藏  举报