拉格朗日插值法
过 n+1 个横坐标互异的点 (x1,y1),(x2,y2),⋯,(xn+1,yn+1) 的 n 次多项式恰为
f(x)=i=1∑n+1yij=i∏xj−xix−xi
证明
将 n+1 个点代入显然得到结论。
模板
[洛谷P4781] 【模板】拉格朗日插值
给出 n 个点,插值出多项式,并求出一个点值,朴素实现是 O(n2) 的。
如果要在取模下实现,记得先把分母都乘起来,然后统一求逆元,这样复杂度依然是 O(n2)的。
参考代码:
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 对 109+7 取模的值。
1≤n≤109,0≤k≤106。
解法
通过魔法我们可以得出答案是关于 n 的 k+1 次多项式。
这时候 O(k2) 的朴素处理就不够了。但是,因为这里用来插值的点是任意的,我们不妨取 1∼k+2 用来插值。
即
f(x)=i=1∑k+2yij=i∏i−jx−j
此时可以发现,上式中的分母就变成了两段阶乘!
化简可得
f(x)=i=1∑k+2(−1)k+2−iyi⋅(i−1)!(k+2−i)![j<i∏(x−i)][j>i∏(x−i)]
这正是我们复杂度的瓶颈,求出 f(n),只需处理 (n−i) 的前缀积、后缀积和阶乘、阶乘逆,如此就可以做到 O(klogk) 解决本题。(插值只需要 O(k),复杂度瓶颈在于求出这 (k+1) 个点和求逆元)
参考代码
练习
[ARC059E] Children and Candies
参考代码
*这道题可以直接暴力预处理出所有的区间 k 次方和,但是你想要拉格朗日插值复杂度也是对的!