其他分享
首页 > 其他分享> > 【模板】拉格朗日插值

【模板】拉格朗日插值

作者:互联网

link

开始学习数学了……

众所周知拉格朗日插值可以解决如下问题:给定N个点,可以在\(O(N^2)\)的时间内求出过这些点的次数和项数都为N-1的多项式,并且求出该多项式在另一个自变量下的取值。

拉格朗日插值的思想是构造。用一句经典的话来说,假如我们有N个项数和次数都为N-1的函数 \(g_1,g_2\dots g_N\) ,并且函数 \(g_i\) 满足

\[g_i(x_j)=\begin{cases}0&j\ne i\\1&j=i\end{cases}(j\in[1,N]) \]

于是可以发现,假如有函数

\[f=\sum\limits_{i=1}^Ng_i\times y_i \]

那么显然这个函数的次数和项数都符合条件,而且某个\(x_i\)只可能在\(g_i\)时有\(y_i\)的贡献,其它时候都被0掉了,所以这个函数是满足上述条件的,也就是说这样构造出的函数是合法的。

但是那个 \(g\) 函数又应当如何构造呢?根据奇怪的因式定理可以尝试构造函数 \(r\):

\[r_i=\prod\limits_{j=1}^N(x-x_j)(j\ne i) \]

那么这个函数 \(r\) 就可以满足上面那个0的条件。那1的条件呢?直接除以一个一样的式子不就好啦。于是:

\[g_i=\frac{r_i}{r_i}=\frac{\prod\limits_{j=1}^N(x-x_j)}{\prod\limits_{j=1}^N(x_i-x_j)}=\prod\limits_{j=1}^N\frac{x-x_j}{x_i-x_j}(j\ne i) \]

合起来就可以得到最终的结论:

\[f=\sum\limits_{i=1}^Ny_i\times\prod\limits_{j=1}^N\frac{x-x_j}{x_i-x_j}(j\ne i) \]

然后发现可以直接带值进行计算。代码挺好写的,有几个地方需要注意一下:

#include<cstdio>
#define zczc
#define int long long
const int mod=998244353;
const int N=2010;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

int m,w,ans,x[N],y[N];

inline int pow(int s1,int s2){
	if(s2==1)return s1;if(s2==0)return 1;
	int an=pow(s1,s2>>1);
	if(s2&1)return an*an%mod*s1%mod;
	else return an*an%mod;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(w);
	for(int i=1;i<=m;i++){read(x[i]);read(y[i]);}
	for(int i=1;i<=m;i++){
		int a=y[i],b=1;
		for(int j=1;j<=m;j++){
			if(i==j)continue;
			a*=w-x[j];a%=mod;
			b*=x[i]-x[j];b%=mod;
		}
		ans+=a*pow(b,mod-2)%mod;ans%=mod;
	}
	printf("%lld",(ans+mod)%mod);
	
	return 0;
}

标签:拉格朗,函数,limits,插值,ne,int,prod,模板,mod
来源: https://www.cnblogs.com/dai-se-can-tian/p/16209462.html