[模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂

Posted ubospica

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂相关的知识,希望对你有一定的参考价值。

多项式

代码

const int nsz=(int)4e5+50;
const ll nmod=998244353,g=3,ginv=332748118ll;


//basic math

ll qp(ll a,ll b){
    ll res=1;
    for(;b;a=a*a%nmod,b>>=1)if(b&1)res=res*a%nmod;
    return res;
}
ll inv(ll n){
    return qp(n,nmod-2);
}


//polynomial operations
//ntt version

namespace npoly{
    //the l means length of array, which means the polynomial has degree l-1
    ////^ for simplifying the doubling process in dft

    typedef int tpoly[nsz];

    tpoly a,b,ans;
    void cl(int *a,int l,int r){memset(a+l,0,(r-l+1)<<2);}
    void cp(int *a,int l,int r,int *b){memcpy(b,a+l,(r-l+1)<<2);}
    
    int len,rev[nsz];
    void fftinit(int l0){
        int l=0;
        while((1<<l)<l0)++l;
        len=(1<<l);
        rep(i,0,len-1){
            rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        }
    }

    void dft(int *a,int len,int fl){
        rep(i,0,len-1)if(i<rev[i])swap(a[i],a[rev[i]]);
        for(int i=1;i<len;i<<=1){
            ll wn=qp((fl==1?g:ginv),(nmod-1)/(i<<1));
            for(int j=0,p=(i<<1);j<len;j+=p){
                ll w=1;
                for(int k=0;k<i;++k,w=w*wn%nmod){
                    ll x=a[j+k],y=a[j+k+i]*w%nmod;
                    a[j+k]=(x+y)%nmod,a[j+k+i]=(x-y+nmod)%nmod;
                }
            }
        }
        if(fl==-1){
            ll v=inv(len);
            rep(i,0,len-1)a[i]=a[i]*v%nmod;
        }
    }
    
    void mul(int *a,int l1,int *b,int l2,int *c){//c=a*b
        static int c1[nsz],c2[nsz];
        fftinit(l1+l2-1);
        cp(a,0,l1-1,c1);
        cl(c1,l1,len-1);
        cp(b,0,l2-1,c2),cl(c2,l2,len-1);

        dft(c1,len,1),dft(c2,len,1);
        rep(i,0,len-1)c1[i]=(ll)c1[i]*c2[i]%nmod;
        dft(c1,len,-1);

        cp(c1,0,l1+l2-2,c);
    }


    void _inverse(int *a,int l0,int *b){
        static int c1[nsz],c2[nsz];
        if(l0==1){b[0]=inv(a[0]);return;}
        _inverse(a,l0>>1,b);
        fftinit(l0<<1);//需要两倍长度dft保证乘法正确
        cp(a,0,l0-1,c1),cl(c1,l0,len-1);
        cp(b,0,(l0>>1)-1,c2),cl(c2,(l0>>1),len-1);

        dft(c1,len,1),dft(c2,len,1);
        rep(i,0,len-1)c2[i]=(ll)c2[i]*(2-((ll)c1[i]*c2[i])%nmod+nmod)%nmod;
        dft(c2,len,-1);

        cp(c2,0,l0-1,b);
    }
    bool inverse(int *a,int l0,int *b){//1 succeed;  0 fail
        if(a[0]==0)return 0;
        static int c1[nsz];
        int l1=1;
        while(l1<l0)l1<<=1;
        cp(a,0,l0-1,c1),cl(c1,l0,l1-1);
        _inverse(c1,l1,b);
        cl(b,l0,l1-1);
        return 1;
    }
    void dncfft(int *a,int l0,int *b){
        static int c1[nsz];
        rep(i,0,l0-1)c1[i]=nmod-a[i];//a[i]<nmod
        c1[0]=(c1[0]+1)%nmod;
        inverse(c1,l0,b);
    }

    void derivative(int *a,int l0,int *b){//b could = a
        rep(i,1,l0-1)b[i-1]=(ll)a[i]*i%nmod;
        b[l0-1]=0;
    }
    void integrate(int *a,int l0,int *b){
        repdo(i,l0-2,0)b[i+1]=(ll)inv(i+1)*a[i]%nmod;
        b[0]=0;
    }
    bool ln(int *a,int l0,int *b){//1 succeed;  0 fail
        if(a[0]==0)return 0;
        static int c1[nsz],c2[nsz];
        derivative(a,l0,c1);
        inverse(a,l0,c2);
        mul(c1,l0,c2,l0,b);
        integrate(b,l0,b);
        return 1;
    }
    void _exp(int *a,int l0,int *b){
        static int c1[nsz];
        if(l0==1){b[0]=1;return;}
        _exp(a,l0>>1,b);
        ln(b,l0,c1);
        rep(i,0,l0)c1[i]=(a[i]-c1[i]+nmod)%nmod;
        c1[0]=(c1[0]+1)%nmod;
        mul(c1,l0,b,l0,b);
    }
    bool exp(int *a,int l0,int *b){//1 succeed;  0 fail
        if(a[0])return 0;
        static int c1[nsz];
        int l1=1;
        while(l1<l0)l1<<=1;
        rep(i,0,l1)c1[i]=(i<l0?a[i]:0);
        _exp(c1,l1,b);//a[l0..(l1-1)] should be 0
        return 1;
    }
    void pow(int *a,int l0,int k,int *b){//suppose a[0]!=0;
        static int c1[nsz];
        ln(a,l0,c1);
        rep(i,0,l0-1)c1[i]=(ll)c1[i]*k%nmod;
        exp(c1,l0,b);
    }

    void sq(int *a,int l0,int *b){
        pow(a,l0,inv(2),b);
    }

//tests
    void testfft(){
        int n,m;
        cin>>n>>m,++n,++m;
        rep(i,0,n-1)cin>>a[i];
        rep(i,0,m-1)cin>>b[i];
        mul(a,n,b,m,ans);
        rep(i,0,n+m-2)cout<<ans[i]<<' ';
        cout<<'
';
    }

    void testinv(){
        int n;
        cin>>n;
        rep(i,0,n-1)cin>>a[i];
        inverse(a,n,ans);
        rep(i,0,n-1)cout<<ans[i]<<' ';
        cout<<'
';
    }
    void testdnc(){
        int n;
        cin>>n;
        rep(i,1,n-1)cin>>a[i];
        dncfft(a,n,ans);
        rep(i,0,n-1)cout<<ans[i]<<' ';
        cout<<'
';
    }
    void testln(){
        int n;
        cin>>n;
        rep(i,0,n-1)cin>>a[i];
        ln(a,n,ans);
        rep(i,0,n-1)cout<<ans[i]<<' ';
        cout<<'
';
    }
    void testexp(){
        int n;
        cin>>n;
        rep(i,0,n-1)cin>>a[i];
        exp(a,n,ans);
        rep(i,0,n-1)cout<<ans[i]<<' ';
        cout<<'
';
    }   
    void testsq(){
        int n;
        cin>>n;
        rep(i,0,n-1)cin>>a[i];
        sq(a,n,ans);
        rep(i,0,n-1)cout<<ans[i]<<' ';
        cout<<'
';
    }
}

int n;
int main(){
    ios::sync_with_stdio(0),cin.tie(0);
//  npoly::testfft();
//  npoly::testinv();
//  npoly::testdnc();
//  npoly::testln();
//  npoly::testexp();
    npoly::testsq();
    return 0;
}

以上是关于[模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂的主要内容,如果未能解决你的问题,请参考以下文章

luogu P4725 多项式对数函数 (模板题FFT多项式求逆求导和积分)

模板分治FFT

「总结」多项式生成函数相关

bzoj 3456 城市规划 多项式求逆+分治FFT

Luogu 4721 模板分治 FFT

luogu P4238 多项式求逆 (模板题FFT)