[算法]拉格朗日插值法
## 拉格朗日插值法
给你\(n + 1\)个点\((x,y)\),希望你求出过这几个点的\(n-1\)次多项式。
朴素的想法是把该多项式每一项的系数作为未知数,然后把点代入多项式中求出很多个\(n\)元\(1\)次方程组。然后高斯消元,时间复杂度为\(O(n^3)\)
我们要介绍的拉格朗日插值法本质上来说是一种构造法,而不是去根据点对来想办法求解。
思考:对于当前给出的\(n+1\)个点,若给你一个多项式\(f_i(x)\),该多项式满足当你代入\(x_i\)时,\(f_i(x)=y_i\),否则,\(f_i(x)=0\),那么我们是不是只要把这\(n+1\)个多项式相加起来就可以求出我们想要求的多项式了。
知道了这点后,我们开始构造这\(n+1\)个多项式,具体的,我们构造出的第\(i\)个多项式长的样子像这样:
\(f_i(x) = y_i\prod_{i\neq j}\frac{x-x_j}{x_i-x_j}\)
构造思想即是希望当你代入任何一个\(x_j\neq x_i\)时,该多项式的某一因式为\(0\),当你代入\(x_i\)时,该多项式可分解为\(y_i*1\)。上述的多项式便由此得来。
然后,我们要求的总的多项式\(f(x)=\sum_{i=1}^{n}y_i\prod_{i\neq j}\frac{x-x_j}{x_i-x_j}\)。
你可以把它拆开来求出每一项的系数,总时间复杂度为\(O(n^2)\)。
模板题,已知\(x\)个点,再给你一个\(k\),求\(x-1\)次多项式的某一点的值\(f(k)\)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define maxn 30005
#define mod 998244353
long long co[maxn],xi[maxn],yi[maxn],n,k,ans = 0;
long long qpow(long long x,long long y) {
long long now = 1;
while (y) {
if (y & 1) (now *= x) %= mod;
(x *= x) %= mod;
y >>= 1;
}
return now;
}
int main() {
scanf("%lld%lld\n",&n,&k);
for (int i = 1;i <= n;i++) scanf("%lld%lld",&xi[i],&yi[i]);
for (int i = 1;i <= n;i++) {
long long num = yi[i],num1 = 1;
for (int j = 1;j <= n;j++) {
if (i == j) continue;
(num *= ((k - xi[j] + mod) % mod)) %= mod;
}
for (int j = 1;j <= n;j++) {
if (i == j) continue;
(num1 *= ((xi[i] - xi[j] + mod) % mod)) %= mod;
}
(ans += num * qpow(num1,mod - 2) % mod) %= mod;
}
printf("%lld\n",ans);
return 0;
}