拉格朗日插值学习笔记
拉格朗日插值学习笔记
只是用来存放板子。。。
裸插值
不知道怎么证:
正在问老师,等回复
最新回复:该是啥值就是啥值吧
UPD 2020.5.18 : 来自黄队的解释:过n+1个点的n次多项式只有一个,构造在这n个点满足条件的多项式就行了。
\[f(k)=\sum_{i=0}^{n} y_{i} \prod_{i \neq j} \frac{k-x[j]}{x[i]-x[j]}
\]
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
#define ll long long
ll read(){
ll x=0;int pos=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return pos?x:-x;
}
const int N = 2001;
const ll mod = 998244353;
ll n,k;
ll x[N],y[N];
ll ksm(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll ginv(ll a){
return ksm(a,mod-2);
}
ll lag(){
ll res=0;
for(int i=1;i<=n;i++){
ll t1=1,t2=1;
for(int j=1;j<=n;j++){
if(i==j) continue;
t1=t1*(k-x[j])%mod;
t2=t2*(x[i]-x[j])%mod;
}
res=(res+y[i]*t1%mod*ginv(t2)%mod+mod)%mod;
}
return res;
}
int main(){
n=read(),k=read();
for(int i=1;i<=n;i++){
x[i]=read();y[i]=read();
}
printf("%lld",lag());
return 0;
}
连续插值
那么此时式子变为:
\[f(k)=\sum_{i=0}^{n} y_{i} \prod_{i \neq j} \frac{k-j}{i-j}
\]
处理出
\[pre_i=\prod _{j=0} ^i k-j
\]
\[suf_i=\prod _{j=i}^n k-j
\]
分子:
\[pre_{i-1}*suf_{i+1}
\]
分母:
\[fac[i]*fac[N-i]*(-1)^{N-i}
\]
于是就可以\(nlogn\)了(逆元)
插值2
权当练习NTT了。。。
看到上面阶乘里面的i和n-i,是不是产生了什么想法?
具体地说,这就是一个卷积的形式
那么我们就可以用多项式乘法求出连续的一堆多项式的值了,时间复杂度从O(n)
实现
从题解里蒯出来的
式子是这样的:
\[\sum_{i=0}^{n} f(i) \frac{(m+x) ! /(m+x-n-1) !}{(m+x-i)(-1)^{n-i} !(n-i) !}
\]
然后卷出来往右平移n就行了(