[多項式學習筆記1]拉格朗日插值定理
算法簡介
拉格朗日插值法是以法國18世紀數學家約瑟夫·拉格朗日命名的一種多項式插值方法。
適用問題
拉格朗日插值定理主要是用來解決下面這樣的問題:
給出 n 個點 (xi,yi)(保證 xi 互不相同),要求找出一個過所有點的多項式函數 f(x)。
顯然最直觀的方法是采用高斯消元,但高斯消元時間復雜度較高且有精度誤差
這時候就可以考慮用拉格朗日插值定理了
算法流程
顯然對於每個點,我們嘗試找出一個函數 fi(x),使得 fi(xi) = yi, 並且對於其他的所有橫坐標 xj(j!=i) 有 fi(xj) = 0。那么把 n 個 fi(x) 加起來就能得到要求的函數 f(x) 了
可以推出式子:
時間復雜度 O(n^2)
代碼(luogu模板)
#include<bits/stdc++.h> #define ll long long using namespace std; inline ll read() { ll f = 1 , x = 0; char ch; do { ch = getchar(); if(ch=='-') f=-1; } while(ch<'0'||ch>'9'); do { x=(x<<3) + (x<<1) + ch - '0'; ch = getchar(); }while(ch>='0'&&ch<='9'); return f*x; } const int MAXN = 2000 + 10; const ll MOD = 998244353; inline ll Pow(ll a,ll b) { ll ans = 1,mul = a; while(b) { if(b&1) ans = (ans * mul) % MOD; mul = (mul * mul)%MOD; b>>=1; } return ans; } inline ll inv(ll a) { return Pow(a,MOD-2); } ll n,k; ll x[MAXN],y[MAXN]; ll ans; int main() { n = read(),k = read(); for(int i=1;i<=n;i++) x[i] = read(),y[i] = read(); for(int i=1;i<=n;i++) { ll res1 = y[i] % MOD; ll res2 = 1; for(int j=1;j<=n;j++) { if(i == j) continue; res1 = (res1 * (k - x[j]%MOD + MOD)%MOD)%MOD; res2 = (res2 * ((x[i] - x[j]%MOD + MOD)%MOD))%MOD; } ans = (ans + (res1 * inv(res2) % MOD)%MOD) % MOD; } cout << ans << endl; }
拉格朗日插值定理的擴展
- 當X取值連續時,可以通過記錄前綴和和后綴和做到線性時間復雜度
- 重心拉格朗日插值定理:
拉格朗日插值法的公式結構整齊緊湊,在理論分析中十分方便,然而在計算中,當插值點增加或減少一個時,所對應的基本多項式就需要全部重新計算,
於是整個公式都會變化,非常繁瑣。這時可以用重心拉格朗日插值法
將拉格朗日插值定理變形為:
其中 g =
然后另 Ti =
當增加一個點時直接增加ti即可