zoukankan      html  css  js  c++  java
  • 【模板】多项式求逆

    问题描述

    P4328

    给定一个多项式 $F(x)$,请求出一个多项式 $G(x)$,满足 $ F(x) * G(x) equiv 1(mod x^n)$。系数对998244353998244353取模。

    分析

    理论基础

    这是一个递推式且呈平方倍增加,就可以用倍增求多项式逆元,从 $x^1$ 开始推至 $x^{2^m}(2^m geq  n)$即可。初值 $B = A(0)^{-1}$。

    利用NTT可以将多项式乘法优化至 $nlog_2n$,利用主定理计算得总时间复杂度为 $O(nlog_2n)$。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int read() {
        int q=0;char ch=' ';
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
        return q;
    }
    #define RI register int
    typedef long long ll;
    const int mod=998244353,G=3,N=4*100000 + 10;  //同NTT,需要4倍的空间
    int n;
    int a[N],b[N],c[N],rev[N];
    inline int qpow(int x,int k)
    {
        int ans=1;
        while(k)
        {
            if(k&1)
                ans=(ll)ans*x%mod;
            x=(ll)x*x%mod,k>>=1;
        }
        return ans;
    }
    void NTT(int *a,int n,int x) {
        for(RI i=0;i<n;++i) if(i<rev[i]) swap(a[i],a[rev[i]]);
        for(RI i=1;i<n;i<<=1) {
            RI gn=qpow(G,(mod-1)/(i<<1));
            for(RI j=0;j<n;j+=(i<<1)) {
                RI t1,t2,g=1;
                for(RI k=0;k<i;++k,g=1LL*g*gn%mod) {
                    t1=a[j+k],t2=1LL*g*a[j+k+i]%mod;
                    a[j+k]=(t1+t2)%mod,a[j+k+i]=(t1-t2+mod)%mod;
                }
            }
        }
        if(x==1) return;
        int ny=qpow(n,mod-2); reverse(a+1,a+n);
        for(RI i=0;i<n;++i) a[i]=1LL*a[i]*ny%mod;
    }
    void work(int deg,int *a,int *b) {
        if(deg==1) {b[0]=qpow(a[0],mod-2);return;}
        work((deg+1)>>1,a,b);
        RI len=0,orz=1;
        while(orz<(deg<<1)) orz<<=1,++len;
        for(RI i=1;i<orz;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
        for(RI i=0;i<deg;++i) c[i]=a[i];  //C=A
        for(RI i=deg;i<orz;++i) c[i]=0;
        NTT(c,orz,1),NTT(b,orz,1);
        for(RI i=0;i<orz;++i)
            b[i]=1LL*(2-1LL*c[i]*b[i]%mod+mod)%mod*b[i]%mod;  //B = 2B-2CB^2 = (2-CB)B
        NTT(b,orz,-1);
        for(RI i=deg;i<orz;++i) b[i]=0;
    }
    int main()
    {
        n=read();
        for(RI i=0;i<n;++i) a[i]=read();
        work(n,a,b);
        for(RI i=0;i<n;++i) printf("%d ",b[i]);
        return 0;
    }

    参考链接:https://www.luogu.org/problemnew/solution/P4238

  • 相关阅读:
    PDF上添加水印
    java调用POI读取Excel
    搭建Linux的VMware Workstation Pro
    js中两种定时器的设置及清除
    SUI使用经验
    List集合与Array数组之间的互相转换
    jquery操作select
    jquery操作CheckBox
    时间格式
    java 获取路径的各种方法
  • 原文地址:https://www.cnblogs.com/lfri/p/11234854.html
Copyright © 2011-2022 走看看