[算法]拉格朗日插值法

## 拉格朗日插值法

​ 给你\(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;
}
posted @ 2021-01-16 17:21  I11usi0ns  阅读(168)  评论(1编辑  收藏  举报