【模板】拉格朗日插值
作者:互联网
开始学习数学了……
众所周知拉格朗日插值可以解决如下问题:给定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) \]然后发现可以直接带值进行计算。代码挺好写的,有几个地方需要注意一下:
- 除法部分确实需要用逆元,但为了少求几次可以考虑全部乘起来之后再一次性搞定。
- 关于取模,最后答案可能是负数,这就意味着必须要用馍加馍的方法把它强行搞成正数。连Wa三次得出的教训。
#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