CF622F:The Sum of the k-th Powers

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;
}

posted @ 2020-01-03 22:11  zhaoxiaoyun  阅读(161)  评论(0编辑  收藏  举报