【CF622F】自然数幂前缀和 + 拉格朗日插值法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/giftedpanda/article/details/99637317

题目大意是求:\sum_{i = 1}^ni^k = 1^k + 2^k + ... + n^k对 10^9 + 7 取模。

当 k = 1时,

当 k = 2时,

当 k = 3时,

我们可以发现所求答案为k+1次多项式。我们只需要计算出k+2个点,然后应用拉格朗日插值法就可以得到此多项式。

#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 8;
const ll mod = 1e9 + 7;
ll n, k, f[maxn], fact[maxn];
ll power(ll a, ll b)
{
	ll ans = 1;
	a %= mod;
	while(b) {
		if(b & 1) ans = (ans * a) % mod;
		a = (a * a) % mod;
		b >>= 1;
	}
	return ans;
}
int main()
{
	while(scanf("%lld %lld", &n, &k) == 2) {
		f[0] = 0;
		for(int i = 1; i <= k+2; i++) f[i] = (f[i-1] + power(i, k)) % mod;
		if(n <= k+2) {
			printf("%lld\n", f[n]);
			continue;
		}
		fact[0] = 1;
		for(int i = 1; i <= k+2; i++) fact[i] = (fact[i-1] * i) % mod;
		ll cur = 1;
		for(int i = 1; i <= k+2; i++) cur = (cur * (n-i)) % mod;
		ll ans = 0;
		ll sign = 1;
		for(int i = 1; i <= k+2; i++) {
			ll inv1 = power(n-i, mod-2) % mod;
			ll inv2 = power(fact[i-1] % mod * fact[k+2-i] % mod, mod-2);
			if((k+2-i) & 1) sign = -1;
			else sign = 1;
			ans = (ans + sign * inv1 * inv2 % mod * cur % mod * f[i] % mod) % mod;
		}
		ans = (ans + mod) % mod;
		printf("%lld\n", ans);
	}
	return 0;
}
  

猜你喜欢

转载自blog.csdn.net/giftedpanda/article/details/99637317
今日推荐