拉格朗日插值学习笔记
拉格朗日插值学习笔记
插值
什么是插值?插值是一种通过已知的、离散的数据点推算一定范围内的新数据点的方法。
插值的一般形式如下:
已知
个点 ,求 次多项式 满足
初次学习时,可以理解为待定系数法求解析式。只不过解方程(即高斯消元)是
拉格朗日插值
拉格朗日插值是众多插值方式中的一种。设第 人话:作垂直。
构造
如此构造的原因:
每个
都需要过 ,但不能过 。也就是在 处点值为 ,而在 处的值都为 。这样构造出来的 全部加起来才能符合要求。
于是设
将点
则
所以最终
这个公式特别重要,你可以什么都不会,但只需要记住这个公式就可以做题了。要求
constexpr int MAXN=2005,MOD=998244353;
int n,k,x[MAXN],y[MAXN];
int power(int a,int b){
int res=1;
for(;b;a=a*a%MOD,b>>=1)
if(b&1)
res=res*a%MOD;
return res;
}
void add(int&x,int y){
x=x+y>=MOD?x+y-MOD:x+y;
}
int lagrange(int k){
int res=0;
for(int i=1,s1,s2;i<=n;++i){
s1=y[i],s2=1;
for(int j=1;j<=n;++j){
if(i==j) continue;
s1=s1*(k-x[j]+MOD)%MOD;
s2=s2*(x[i]-x[j]+MOD)%MOD;
}
add(res,s1*power(s2,MOD-2)%MOD);
}
return res;
}
signed main(){
n=read(),k=read();
for(int i=1;i<=n;++i) x[i]=read(),y[i]=read();
printf("%lld\n",lagrange(k));
return 0;
}
在 连续时的做法
例题:[CF622F] The Sum of the k-th Powers。
题意:求
其中
这道题的前半部分是证明原式是一个关于
插一个
由于
所以
复杂度
实际上还有一种不用这么复杂的解决方案。将原式化为
其中
这是利用了
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int MAXN=1e6+5,MOD=1e9+7;
int n,k,pre[MAXN],suf[MAXN],fac[MAXN];
int power(int a,int b){
int res=1;
for(;b;a=a*a%MOD,b>>=1)if(b&1)res=res*a%MOD;
return res;
}
int lagrange(int k){
pre[0]=suf[k+3]=fac[0]=1;
for(int i=1;i<=k+2;++i) pre[i]=pre[i-1]*(n-i)%MOD;
for(int i=k+2;i;--i) suf[i]=suf[i+1]*(n-i)%MOD;
for(int i=1;i<=k+2;++i) fac[i]=fac[i-1]*i%MOD;
int res=0;
for(int i=1,y=0,s1,s2;i<=k+2;++i){
y=(y+power(i,k))%MOD;
s1=pre[i-1]*suf[i+1]%MOD;
s2=fac[i-1]*((k-i)&1?-1:1)*fac[k+2-i]%MOD;
res=(res+y*s1%MOD*power(s2,MOD-2)%MOD)%MOD;
}
return res;
}
signed main(){
scanf("%lld%lld",&n,&k);
printf("%lld\n",(lagrange(k)+MOD)%MOD);
return 0;
}
重心拉格朗日插值
拉格朗日插值还有一种特殊情况,那就是动态加点,随时询问。例题:LOJ #165. 拉格朗日插值。
在朴素做法中,加点是
将原式变形
注意最后一步中,我们为了让最外层的
令
则得到最终的式子:
在新增加一个点之后,我们只需
constexpr int MAXN=3005,MOD=998244353;
int n,x[MAXN],y[MAXN],w[MAXN],cnt;
int power(int a,int b){
int res=1;
for(;b;a=a*a%MOD,b>>=1)if(b&1)res=res*a%MOD;
return res;
}
signed main(){
n=read();
while(n--){
int opt=read(),X=read();
if(opt==1){
int Y=read();
x[++cnt]=X,y[cnt]=w[cnt]=Y;
for(int i=1;i<cnt;++i){
w[i]=w[i]*power(x[i]-x[cnt],MOD-2)%MOD;
w[cnt]=w[cnt]*power(x[cnt]-x[i],MOD-2)%MOD;
}
}else{
int s1=1,s2=0;
for(int i=1;i<=cnt;++i)
if(X==x[i]){
write(y[i]);
goto byby;
}
for(int i=1;i<=cnt;++i){
s1=s1*(X-x[i])%MOD;
s2=(s2+w[i]*power(X-x[i],MOD-2)%MOD)%MOD;
}
write((s1*s2%MOD+MOD)%MOD);
byby:;
}
}
return fw,0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】