拉格朗日插值的应用
引言:
什么是拉格朗日插值?假设我们现在有三个点 $(x_1,y_1),(x_2,y_2),(x_3,y_3)$,现在我们要找一条唯一的二次曲线刚好经过这三个点。
拉格朗日给出了一个绝妙的方法,他把我们要求的曲线的表达式等同于三个函数的累加。具体是这么操作的:
第一个函数保证$f_1(x_1)=1,f_1(x_2)=f_1(x_3)=0$
第二个函数保证$f_2(x_2)=1,f_2(x_1)=f_2(x_3)=0$
第三个函数保证$f_3(x_3)=1,f_3(x_1)=f_3(x_2)=0$
那么我们所要求的函数即为:
实现:
一般情况下拉格朗日插值的复杂度是$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
41
using namespace std;
const int N = 1e6+100;
typedef long long ll;
const ll mod = 998244353;
struct point{
	ll x,y;
}p[N];
int n,k;
ll qpow(ll a,ll b,ll mod){
	ll ans=1;
	while(b){
		if(b&1){
			ans=(ans%mod*a%mod)%mod;
		}
		a=(a%mod*a%mod)%mod;
		b>>=1;
	}
	return ans%mod;
}
ll Lagrange(int k){
	ll ans=0;
	for(int j=1;j<=n;j++){//
		ll base1=1;
		ll base2=1;
		for(int i=1;i<=n;i++){//lj(k)基函数 
			if(j==i) continue;
			base1=(base1%mod*((k-p[i].x)%mod+mod)%mod)%mod;
			base2=(base2%mod*((p[j].x-p[i].x)%mod+mod)%mod)%mod;
		}
		ans=(ans%mod+(p[j].y%mod*base1%mod*qpow(base2,mod-2,mod)%mod)%mod)%mod;
	}
	return ans;
} 
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
	cout<<Lagrange(k)<<endl;
	return 0;
}
如果已知的坐标是连续的话,那么我们可以通过预处理使得复杂度变为$O(n)$,代码以codeforces 622F为例。
1  | 
  | 
总结:
其实拉格朗日插值在算法竞赛中主要用于数据分析,即对于给定的某些关系构造出若干已知点,然后利用这些已知点去计算通项公式。