拉格朗日插值总结

拉格朗日插值总结

  • 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=0nyii=jx[i]x[j]kx[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=0ikj s u f [ i ] = ∏ j = i u p k − j suf[i]=\prod\limits_{j=i}^{up}k-j suf[i]=j=iupkj

    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=0nyi(1)nifac[n]fac[ni]pre[i]suf[i+1]

  • 重心拉格朗日插值

    h = ∏ i = 0 n x − x i h=\prod\limits_{i=0}^{n}x-x_i h=i=0nxxi 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=ixixjyi

    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=0nxxiti

    每次加入一个新点, 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) (xx1)(xx2)...(xxn)

常用套路是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;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值