拉格朗日插值总结
- n + 1 n+1 n+1个 x x x不同的点可以确定一个 n n n次多项式
f ( k ) = ∑ i = 0 n y i ∏ i ≠ j k − x [ j ] x [ i ] − x [ j ] f(k)=\sum\limits_{i=0}^{n}y_i\prod\limits_{i\neq j}\frac{k-x[j]}{x[i]-x[j]} f(k)=i=0∑nyii=j∏x[i]−x[j]k−x[j]
-
x不连续的时候的时候直接 O ( n 2 ) O(n^2) O(n2)计算
-
x取值连续的时候的做法 ( x i = i ) (x_i=i) (xi=i) O ( n ) O(n) O(n)
p r e [ i + 1 ] = ∏ j = 0 i k − j pre[i+1]=\prod\limits_{j=0}^{i}k-j pre[i+1]=j=0∏ik−j s u f [ i ] = ∏ j = i u p k − j suf[i]=\prod\limits_{j=i}^{up}k-j suf[i]=j=i∏upk−j
p r e [ 0 ] = s u f [ u p + 1 ] = 1 pre[0]=suf[up+1]=1 pre[0]=suf[up+1]=1
f [ k ] = ∑ i = 0 n y i p r e [ i ] ∗ s u f [ i + 1 ] ( − 1 ) n − i f a c [ n ] f a c [ n − i ] f[k]=\sum\limits_{i=0}^{n}y_i\frac{pre[i]*suf[i+1]}{(-1)^{n-i}fac[n]fac[n-i]} f[k]=i=0∑nyi(−1)n−ifac[n]fac[n−i]pre[i]∗suf[i+1]
-
重心拉格朗日插值
h = ∏ i = 0 n x − x i h=\prod\limits_{i=0}^{n}x-x_i h=i=0∏nx−xi t i = ∏ j ≠ i y i x i − x j t_i=\prod\limits_{j\neq i}\frac{y_i}{x_i-x_j} ti=j=i∏xi−xjyi
f ( x ) = h ∑ i = 0 n t i x − x i f(x)=h\sum\limits_{i=0}^{n}\frac{t_i}{x-x_i} f(x)=hi=0∑nx−xiti
每次加入一个新点, O ( n ) O(n) O(n)计算 t i t_i ti和更新别的点的 t i t_i ti, O ( n ) O(n) O(n)求h, O ( n ) O(n) O(n)求 ∑ \sum ∑得出 f ( x ) f(x) f(x)
-
求多项式系数 $O(n^2)长乘法求系数 $ O ( n ) 求 f ( k ) O(n)求f(k) O(n)求f(k)
( x − x 1 ) ( x − x 2 ) . . . ( x − x n ) (x-x_1)(x-x_2)...(x-x_n) (x−x1)(x−x2)...(x−xn)
常用套路是n次多项式前缀和转为 n + 1 n+1 n+1次多项式,多插一个点再求和
struct Lglr{
void init(){
fac[1]=fac[0]=1;
for(int i=2;i<maxn;++i)fac[i]=fac[i-1]*i%mod;
facinv[maxn-1]=mypow(fac[maxn-1],mod-2);
for(int i=maxn-2;i>=0;--i)
facinv[i]=facinv[i+1]*(i+1)%mod;
}
//给定(0,f0)...(up,fup)求 up次多项式 f(x)的值 O(n)
ll cal(ll x,ll*a,int up){//pre往偏移一位
if(x<=up)return a[x];
pre[0]=1;suf[up+1]=1;
for(int i=0;i<=up;++i)pre[i+1]=(x-i)%mod*pre[i]%mod;
for(int i=up;i>=0;--i)suf[i]=(x-i)%mod*suf[i+1]%mod;
ll ans=0;
for(int i=0;i<=up;++i){
ll f=a[i]*pre[i]%mod*suf[i+1]%mod*facinv[i]%mod*facinv[up-i]%mod;
if((up-i)&1)ans=(ans-f+mod)%mod;
else ans=(ans+f)%mod;
}
return ans;
}
//给定n+1个点,求n次多项式f(k)的值 O(n^2)
ll inv(int x){return mypow(x,mod-2);}
ll cal2(ll k,ll*x,ll*y){
for(int i=0;i<=n;++i)cin>>x[i]>>y[i];
ll ans=0;
for(int i=0;i<=n;++i){
ll zi=y[i],mu=1;
for(int j=0;j<=n;++j){
if(i!=j){
zi=zi*(k-x[j])%mod;
mu=mu*(x[i]-x[j])%mod;
}
}
ans=(ans+zi*inv(mu)%mod)%mod;
}
return (ans+mod)%mod;
}
//O(n^2)求多项式 O(n)单点求f(k)
ll a[maxn], b[maxn], c[maxn], temp[maxn];
ll x[maxn], y[maxn];
int n;
void mul(ll *f, int len, ll t) { //len为多项式的次数+1,函数让多项式f变成f*(x+t)
for (int i = len; i > 0; --i)
temp[i] = f[i], f[i] = f[i - 1];
temp[0] = f[0], f[0] = 0;
for (int i = 0; i <= len; ++i)
f[i] = (f[i] + t * temp[i]) % mod;
}
void dev(ll *f, ll *r, ll t) { //f是被除多项式的系数,r保存f除以x+t的结果
for (int i = 0; i <= n; ++i)
temp[i] = f[i];
for (int i = n; i > 0; --i) {
r[i - 1] = temp[i];
temp[i - 1] = (temp[i - 1] - t * temp[i]) % mod;
}
}
void lglr() {
memset(a, 0, sizeof a);
b[1] = 1, b[0] = -x[1];
for (int i = 2; i <= n; ++i) {
mul(b, i, -x[i]);
}//预处理(x-x1)*(x-x2)...*(x-xn)
for (int i = 1; i <= n; ++i) {
ll fz = 1;
for (int j = 1; j <= n; ++j) {
if (j == i)
continue;
fz = fz * (x[i] - x[j]) % mod;
}
fz = qpow(fz, mod - 2);
fz = fz * y[i] % mod; //得到多项式系数
dev(b, c, -x[i]);//得到多项式,保存在c数组
for (int j = 0; j < n; ++j)
a[j] = (a[j] + fz * c[j]) % mod;
}
}
ll sum(){//n点n-1次多项式
cin >> n >> k;
for (int i = 1; i <= n; ++i)
scanf("%lld%lld", &x[i], &y[i]);
lglr();
ll ans = 0,res=1;
for (int i = 0; i < n; ++i) {
ans = (ans + res * a[i]) % mod;
res = res * k % mod;
}
return (ans+mod)%mod;
}
}lglr;