拉格朗日插值学习笔记
众所周知,\(n+1\) 个 \(x\) 不同的坐标会确定一个最高次为 \(n\) 的多项式,使其函数图像经过所有坐标
最简单的方法就是高斯消元,但是是 \(O(n^3)\) 的,考虑更快的方法
可以先让每个点先找到自己的投影点,也就是 \((x,0)\)
接下来对于每一个点 \(i\),求出一个函数 \(g_i(x)\),使它进过点 \(i\) 和其他点的投影点
此时 \(f(x)=\sum_{i=1}^n g_i(x)\)
设 \(g_i(x)=a*\prod_{j\neq i} (x-x_j)\),将 \((x_i,y_i)\) 代入得 \(a=\dfrac{y_i}{\prod_{j\neq i} (x_i-x_j)}\),所以:
\[g_i(x)=\prod_{j\neq i} (x-x_j)*\dfrac{y_i}{\prod_{j\neq i} (x_i-x_j)}=y_i*\prod_{j\neq i} \dfrac{x-x_j}{x_i-x_j}
\]
最后相加即可
https://www.gxyzoj.com/d/gxyznoi/p/270
令 \(x=k\),然后直接求就行了
点击查看代码
#include<cstdio>
#define ll long long
using namespace std;
const int mod=998244353;
int n,k,x[2005],y[2005];
ll qpow(ll x,int y)
{
ll res=1;
while(y)
{
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
}
ll ans=0;
for(int i=1;i<=n;i++)
{
ll tmp=y[i];
for(int j=1;j<=n;j++)
{
if(i==j) continue;
tmp=tmp*(k-x[j])%mod*qpow(x[i]-x[j],mod-2)%mod;
}
ans=(ans+tmp)%mod;
}
printf("%lld",(ans+mod)%mod);
return 0;
}
接下来看怎么把系数弄出来,最简单的方法是 \(O(n^3)\) 暴力背包,但是可以发现主要的时间花在了处理分子上
注意到不考虑 \(i\),时,分子都是相同的,可以先单独算出来,再依次去除
记 \(g(x)=\prod_{i-1}^n (x-x_i)\),\(f(x)_i\) 表示 \(i\) 次项系数
所以 \(g(x)_0=-x_jfj(x)_0,g(x)_i=fj(x)_{i-1} -x_jfj(x)_i\)
所以 \(fj(x)_0=-g(x)_0/x_j,fj(x)_i=(fj(x)_{i-1} -g(x)_i)/x_j\)
点击查看代码
void lagrange(int n)
{
for(int i=1;i<=n;i++) c[i]=1;
for(int i=1;i<=n;i++)
{
// printf("%d %d\n",x[i],y[i]);
inv[i]=qpow(x[i],mod-2);
for(int j=1;j<=n;j++)
{
if(j!=i) c[i]=c[i]*(x[i]-x[j]+mod)%mod;
}
c[i]=qpow(c[i],mod-2)*y[i]%mod;
}
tmp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=i;j>=0;j--)
{
tmp[j]=(tmp[j-1]-x[i]*tmp[j]%mod+mod)%mod;
}
}
for(int i=1;i<=n;i++)
{
t[0]=mod-tmp[0]*inv[i]%mod;
for(int j=1;j<n;j++)
{
t[j]=((t[j-1]-tmp[j])*inv[i]%mod+mod)%mod;
}
for(int j=0;j<n;j++) f[j]=(f[j]+t[j]*c[i])%mod;
}
// for(int i=0;i<n;i++) f[i]=f[i+2];
}

浙公网安备 33010602011771号