拉格朗日插值法

拉格朗日插值法是一种多项式插值方法。简单来说,给定 n n n 个点,它可以唯一地构造出经过这些点的 n − 1 n-1 n1 次函数。
如何实现呢?其实非常地暴力:记我们给定的点为 ( a i , b i ) (a_i,b_i) (ai,bi),我们只需要构造出一些函数 f i ( x ) f_i(x) fi(x) 使得 f i ( x ) f_i(x) fi(x) 满足 f ( a i ) = b i f(a_i)=b_i f(ai)=bi f ( a j ) = 0 f(a_j)=0 f(aj)=0 j ≠ i j≠i j̸=i 即可。
接下来介绍“开关函数” p i ( x ) p_i(x) pi(x) p i ( x ) p_i(x) pi(x) 满足当 x = a i x=a_i x=ai p i ( x ) = 1 p_i(x)=1 pi(x)=1 x = a j x=a_j x=aj j ≠ i j\ne i j̸=i p i ( x ) = 0 p_i(x)=0 pi(x)=0。这样 f i ( x ) = p i ( x ) b i f_i(x)=p_i(x)b_i fi(x)=pi(x)bi
如何实现上述功能呢?我们考虑一个简单的数学性质: i / i = 0 i/i=0 i/i=0 0 / i = 0 0/i=0 0/i=0 i ≠ 0 i\ne0 i̸=0。这样我们只需要让 x = a i x=a_i x=ai 时分子分母一定相等, x x x 为其他的 a a a 值时分母一定出现 0 0 0 即可。可以得到: p i = ∏ j = 1 , j ≠ i n x − a j a i − a j p_i=\prod_{j=1,j\ne i}^{n}\frac{x-a_j}{a_i-a_j} pi=j=1,j̸=inaiajxaj。考虑这样的 p i p_i pi 为什么拥有上述性质:当 x = a i x=a_i x=ai 时,无论 j j j 为何值,分子分母一定相等,即 p i = 1 p_i=1 pi=1;当 x = a m x=a_m x=am m ≠ i m\ne i m̸=i 时,由于 j ≠ i j\ne i j̸=i,故必然存在 j = m j=m j=m,此时分子为 0 0 0 p i = 0 p_i=0 pi=0
综上所述,我们可以给出一般地过点集 { ( a i , b i ) } \{(a_i,b_i)\} {(ai,bi)} 的多项式插值公式:
F ( n ) = ∑ i = 1 n f i ( n ) = ∑ i = 1 n b i ∏ j = 1 , j ≠ i n n − a j a i − a j \begin{array}{lll} F(n)&=&\sum_{i=1}^nf_i(n)\\ &=&\sum_{i=1}^nb_i\prod_{j=1,j\ne i}^n\frac{n-a_j}{a_i-a_j} \end{array} F(n)==i=1nfi(n)i=1nbij=1,j̸=inaiajnaj
注意其中 i i i j j j n n n 的区别。

例题

The sum of the K-th Powers

给出两个非负整数 n n n k k k,求
∑ i = 1 n i k \sum_{i=1}^ni^k i=1nik
答案对 1 0 9 + 7 10^9+7 109+7 取模。
n ≤ 1 0 9 n\le10^9 n109 k ≤ 1 0 6 k\le10^6 k106

题解

暴力计算显然实现复杂度无法承受。
F ( n ) = ∑ i = 1 n i k F(n)=\sum_{i=1}^ni^k F(n)=i=1nik
首先分析当 k k k 较小的情况。 k = 1 k=1 k=1 时, F ( n ) = n ( n + 1 ) / 2 F(n)=n(n+1)/2 F(n)=n(n+1)/2 k = 2 k=2 k=2 时, F ( n ) = n ( n + 1 ) ( 2 n + 1 ) / 6 F(n)=n(n+1)(2n+1)/6 F(n)=n(n+1)(2n+1)/6;依此类推,可以发现 F ( n ) F(n) F(n) 是关于 n n n k + 1 k+1 k+1 次多项式。
既然如此,我们可以通过先暴力算出一部分多项式上的点,然后通过插值得出多项式关于 n n n 的函数形式,再直接通过函数求值。
我们知道,确定一个 n n n 次函数需要 n + 1 n+1 n+1 个点,故我们首先暴力算出 F ( 1 ) , F ( 2 ) , . . . , F ( k + 2 ) F(1),F(2),...,F(k+2) F(1),F(2),...,F(k+2)。然后,我们将这些点代入拉格朗日插值公式得
F ( n ) = ∑ i = 1 k + 2 F ( i ) ∏ j = 1 , j ≠ i k + 2 n − j i − j F(n)=\sum_{i=1}^{k+2}F(i)\prod_{j=1,j\ne i}^{k+2}\frac{n-j}{i-j} F(n)=i=1k+2F(i)j=1,j̸=ik+2ijnj
然后就到了愉快的拆式子时间了。
F ( n ) = ∑ i = 1 k + 2 F ( i ) ( ∏ j = 1 k + 2 ( n − j ) ) / ( n − i ) ( i − 1 ) ! ( k + 2 − i ) ! ( − 1 ) k + 2 − i F(n)=\sum_{i=1}^{k+2}F(i)\frac{(\prod_{j=1}^{k+2}(n-j))/(n-i)}{(i-1)!(k+2-i)!(-1)^{k+2-i}} F(n)=i=1k+2F(i)(i1)!(k+2i)!(1)k+2i(j=1k+2(nj))/(ni)
这样只需要通过预处理得出分母中阶乘的逆元,并通过费马小定理求出 i − 1 i-1 i1 的逆元即可在 O ( k log ⁡ k ) O(k\log k) O(klogk) 的时间内得出答案。

代码

#include <iostream>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const unsigned MOD = 1E9 + 7;
const unsigned MAXN = 1E6;
const unsigned N = MAXN + 10;
unsigned n, k;
unsigned inv[N];
unsigned f[N];
void init() {
    inv[0] = inv[1] = 1;
    for (int i = 2; i <= k + 2; i++) {
        inv[i] = (-ll(MOD / i) * inv[MOD % i] % MOD + MOD) % MOD;
    }
    for (int i = 2; i <= k + 2; i++) {
        inv[i] = ull(inv[i - 1]) * inv[i] % MOD;
    }
}
unsigned pow(unsigned a, unsigned b) {
    unsigned res = 1;
    while (b) {
        if (b & 1) {
            res = ull(res) * a % MOD;
        }
        a = ull(a) * a % MOD;
        b >>= 1;
    }
    return res;
}
main() {
    ios::sync_with_stdio(false);
    cin >> n >> k;
    init();
    for (unsigned i = 1; i <= k + 2; i++) {
        f[i] = (f[i - 1] + pow(i, k)) % MOD;
    }
    if (n <= k + 2) {
        cout << f[n];
        return 0;
    }
    unsigned t = 1;
    for (unsigned i = 1; i <= k + 2; i++) {
        t = ull(t) * (n - i) % MOD;
    }
    unsigned ans = 0;
    for (unsigned i = 1; i <= k + 2; i++) {
        ans = (ans + ((ll(ull(f[i]) * t % MOD * pow(n - i, MOD - 2) % MOD * inv[i - 1] % MOD * inv[k + 2 - i] % MOD) * (((k + 2 - i) & 1) ? -1 : 1)) + MOD) % MOD) % MOD;
    }
    cout << ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值