拉格朗日插值法

n+1n+1 个横坐标互异的点 (x1,y1),(x2,y2),,(xn+1,yn+1)(x_1,y_1),(x_2,y_2),\cdots,(x_{n+1},y_{n+1})nn 次多项式恰为

f(x)=i=1n+1yijixxixjxif(x) = \sum_{i=1}^{n+1} y_i \prod_{j\neq i} \dfrac{x-x_i}{x_j-x_i}

证明

n+1n+1 个点代入显然得到结论。

模板

[洛谷P4781] 【模板】拉格朗日插值

给出 nn 个点,插值出多项式,并求出一个点值,朴素实现是 O(n2)O(n^2) 的。

如果要在取模下实现,记得先把分母都乘起来,然后统一求逆元,这样复杂度依然是 O(n2)O(n^2)的。

参考代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<bits/stdc++.h>
using namespace std;

using ll=long long;
const int MOD = 998244353;

int ksm(int a,int b){
int r=1;
while(b){
if(b&1)r=(ll)r*a%MOD;
a=(ll)a*a%MOD;
b>>=1;
}
return r;
}
int inv(int x){return ksm(x,MOD-2);}

const int N = 2e3+5;
int px[N],py[N];

int main(){
ios::sync_with_stdio(0);cin.tie(0);

int n,k; cin>>n>>k;
for(int i=1;i<=n;i++)cin>>px[i]>>py[i];

int ans = 0;
for(int i=1;i<=n;i++){
int num=1,deno=1; // 分子,分母
for(int j=1;j<=n;j++){
if(j==i)continue;
num = (ll)num*(k-px[j]+MOD)%MOD;
deno = (ll)deno*(px[i]-px[j]+MOD)%MOD;
}
ans = (ans + (ll)num*inv(deno)%MOD*py[i]%MOD)%MOD;
}

cout << ans << '\n';
return 0;
}

例题

[CF622F] The Sum of the k-th Powers

题意

i=1nik\sum_{i=1}^n i^k109+710^9+7 取模的值。

1n109,0k1061\le n \le 10^9, 0\le k \le 10^6

解法

通过魔法我们可以得出答案是关于 nnk+1k+1 次多项式。

这时候 O(k2)O(k^2) 的朴素处理就不够了。但是,因为这里用来插值的点是任意的,我们不妨取 1k+21 \sim k+2 用来插值。

f(x)=i=1k+2yijixjijf(x) = \sum_{i=1}^{k+2} y_i \prod_{j\neq i} \dfrac{x-j}{i-j}

此时可以发现,上式中的分母就变成了两段阶乘!

化简可得

f(x)=i=1k+2(1)k+2iyi[j<i(xi)][j>i(xi)](i1)!(k+2i)!f(x) = \sum_{i=1}^{k+2} (-1)^{k+2-i}y_i \cdot \dfrac{\left[\displaystyle\prod_{j < i}{(x-i)} \right]\left[\displaystyle\prod_{j > i}{(x-i)}\right]}{(i-1)!(k+2-i)!}

这正是我们复杂度的瓶颈,求出 f(n)f(n),只需处理 (ni)(n-i) 的前缀积、后缀积和阶乘、阶乘逆,如此就可以做到 O(klogk)O(k\log k) 解决本题。(插值只需要 O(k)O(k),复杂度瓶颈在于求出这 (k+1)(k+1) 个点和求逆元)

参考代码

练习

[ARC059E] Children and Candies
参考代码

*这道题可以直接暴力预处理出所有的区间 kk 次方和,但是你想要拉格朗日插值复杂度也是对的!