CF622F:The Sum of the k-th Powers
题意:
- 求\(\sum_{i=1}^ni^k\),结果模\(1e9+7\)。
思路:
- 拉格朗日插值法。
- 看大部分题解发现说是\(\sum_{i=1}^ni^k\)是一个\(k+1\)次多项式,可是我实在是看不出来,所以接下来证明一下。
- 首先看一个等差数列:
- \(1,2,3,...,n\)。
- 之后做差分操作:
- \(2-1,3-2,...,n-(n-1)\).
- \(1,1,1,...,1\).
- 对于这样一个数列,我们称之为常数数列。
- 所以我们现在有等差数列:
- \(a_1,a_2,...,a_n\).
- 做差分后
- \(a_2-a_1,a_3-a_2,...,a_n-a_{n-1}\).
- \(b_1,...,b_{n-1}\).
- 我们知道\(b_i=d\),其中\(d\)为公差。
- 那当然此时的\(\{a\}\)是等差数列,所以\(b_i\)会全部相等,但假如说\(\{a\}\)是一般的数列呢?
- 同样做差,我们得到\(\{b\}\)序列,称之为数列\(\{a\}\)的阶差数列。
- 那么再对数列\(\{b\}\)做差分,就可以得到二阶阶差数列。
- 同样的我们可以有三阶,四阶...。
- 如果\(\{a\}\)的\(p\)阶差数列是一个非\(0\)的常数数列,那么就称数列\(\{a\}\)为\(p\)阶等差数列。
定理:
- 数列\(\{a\}\)是一个\(p\)阶等差数列的充要条件是通项\(a_x\)为\(x\)的一个\(p\)次多项式。
简单的证明:
- 已知一个数列\(\{a\}\)是一个\(p\)阶等差数列,设\(\{a\}\)的通项\(a_x\)是一个关于\(x\)的\(v\)次多项式,即\(f(x)=\sum_{i=0}^vu_i*x^i\)。其中\(u_i\)是\(x^i\)的系数。
- 做一阶差分可得:
- \(\Delta f(x)=f(x+1)-f(x)=\sum_{i=0}^vu_i*(x+1)^i-\sum_{i=0}^vu_i*x^i\).
- 只考虑\(x^v\)。
- \(u_v*(x+1)^v-u_v*x^v\).
- 二项式定理展开\((x+1)^v\),因为只考虑\(x^v\),所以\(x^v\)的系数为\(1\)。
- \(u_v*x^v-u_v*x^v=0\).
- 所以可知,在一次差分后,\(x^v\)项被消除了,所以我们知道每做一次差分,得到数列的通项的多项式次数会减一。
- 又因为\(\{a\}\)是一个\(p\)阶等差数列,所以数列\(\{a\}\)在做\(p\)次差分后,会得到一个\(0\)次多项式,也就是常数。
回到题目
- 此时序列\(\{a\}\)为:
- \(\sum_{i=1}^0i^k,\sum_{i=1}^1i^k,\sum_{i=1}^2i^k,...,\sum_{i=1}^ni^k\).
- 差分后有:
- \(\sum_{i=1}^1i^k-\sum_{i=1}^0i^k,\sum_{i=1}^2i^k-\sum_{i=1}^1i^k,...,\sum_{i=1}^ni^k-\sum_{i=1}^{n-1}i^k\).
- 也就是\(1^k,2^k,...,n^k\)。
- 这个数列的通项为\(f(x)=x^k\),是一个\(k\)次多项式。
- 题目要求\(\sum_{i=1}^ni^k\),又知差分序列求前缀和为原序列。
- 所以原序列为所求。
- 我们又知每次差分后数列通项的多项式次数会减一,差分序列的次数为\(k\),所以数列\(\{a\}\)是一个关于\(n\)的\(k+1\)次多项式。
- 所以我们只需要插值搞出这个\(k+1\)次多项式即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int maxn = 1e6 + 10;
ll pre[maxn], suf[maxn], fac[maxn];
ll n, k, ans;
ll qmi(ll a, ll b)
{
ll res = 1; res %= mod;
while(b)
{
if(b&1) res = res*a%mod;
a = (a*a)%mod;
b >>= 1;
} return res % mod;
}
void init()
{
pre[0] = suf[k+3] = fac[0] = 1;
for(int i = 1; i <= k+2; i++)
pre[i] = pre[i-1]*(n-i) % mod;
for(int i = k+2; i >= 1; i--)
suf[i] = suf[i+1]*(n-i) % mod;
for(int i = 1; i <= k+2; i++)
fac[i] = fac[i-1]*i % mod;
}
void Lagrange()
{
ll y = 0;
for(int i = 1; i <= k+2; i++)
{
y = (y + qmi(i, k)) % mod;
ll a = pre[i-1]*suf[i+1] % mod;
ll b = fac[i-1]*((k-i)&1 ? -1ll : 1ll)*fac[k+2-i] % mod;
ans = (ans + y*a%mod * qmi(b, mod-2)) % mod;
} cout << (ans + mod) % mod << endl;
}
int main()
{
scanf("%lld%lld", &n, &k);
init(); Lagrange();
return 0;
}
原文地址:https://www.cnblogs.com/zxytxdy/p/12147208.html
时间: 2024-11-05 20:31:28