「CF622F」The Sum of the k-th Powers「拉格朗日插值」

题意

\(\sum_{i=1}^n i^k\)\(n \leq 10^9,k \leq 10^6\)

题解

观察可得答案是一个\(k+1\)次多项式,我们找\(k+2\)个值带进去然后拉格朗日插值

\(n+1\)组点值\((x_i,y_i)\),得到\(n\)次多项式\(f\)的拉格朗日插值方法:

\[f(x) = \sum_{i = 0}^n y_i\prod_{j\not =i} \frac{x-x_j}{x_i-x_j} \]

时间复杂度为\(O(n^2)\).

现在考虑这题,我们把\(1\)\(k+2\)带入,有很好的性质:对于每个\(i\),分母是\(1\)乘到\(i-1\)再乘上\(-1\)乘到\(i-k-2\),这可以预处理阶乘\(O(1)\)处理。分子可以预处理前后缀积来\(O(1)\)得到

于是时间复杂度为\(O(n)\),可以通过

#include <algorithm>
#include <cstdio>
using namespace std;

const int mo = 1e9 + 7;
const int N = 1e6 + 10;

int pl[N], pr[N], fac[N];

int qpow(int a, int b) {
    int ans = 1;
    for(; b >= 1; b >>= 1, a = 1ll * a * a % mo)
        if(b & 1) ans = 1ll * ans * a % mo;
    return ans;
}

int main() {
    int n, k, y = 0, ans = 0;
    scanf("%d%d", &n, &k);
    pl[0] = pr[k + 3] = fac[0] = 1;
    for(int i = 1; i <= k + 2; i ++)
        pl[i] = 1ll * pl[i - 1] * (n - i) % mo;
    for(int i = k + 2; i >= 1; i --)
        pr[i] = 1ll * pr[i + 1] * (n - i) % mo;
    for(int i = 1; i <= k + 2; i ++)
        fac[i] = 1ll * fac[i - 1] * i % mo;
    for(int i = 1; i <= k + 2; i ++) {
        y = (y + qpow(i, k)) % mo;
        int a = pl[i - 1] * 1ll * pr[i + 1] % mo;
        int b = fac[i - 1] * ((k - i) & 1 ? -1ll : 1ll) * fac[k + 2 - i] % mo;
        ans = (ans + 1ll * y * a % mo * qpow(b, mo - 2) % mo) % mo;
    }
    printf("%d\n", (ans + mo) % mo);
    return 0;
}

posted @ 2019-02-13 19:52  hfhongzy  阅读(246)  评论(0编辑  收藏  举报