多项式

  • 并没有讲解.只是记录用.

\(FFT\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN=4e6+10;
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(; !isdigit(ch); ch=getchar())
        if(ch=='-')
            pos=0;
    for(; isdigit(ch); ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
struct cp
{
    double x,y;
    cp(double xx=0,double yy=0)
    {
        x=xx;
        y=yy;
    }
    cp operator +(const cp &b) const
    {
        return cp(x+b.x,y+b.y);
    }
    cp operator -(const cp &b) const
    {
        return cp(x-b.x,y-b.y);
    }
    cp operator *(const cp &b) const
    {
        return cp(x*b.x-y*b.y,x*b.y+y*b.x);
    }
};
const double PI=acos(-1.0);
int rev[MAXN];
void init(int n,int lim)
{
    for(int i=0; i<n; ++i)
    {
        for(int j=0; j<lim; ++j)
            if((i>>j)&1)
                rev[i]|=1<<(lim-j-1);
    }
}
void FFT(cp *a,int n,bool invflag)
{
    for(int i=0; i<n; ++i)
    {
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    }
    for(int l=2; l<=n; l<<=1)
    {
        int m=l>>1;
        cp wi=cp(cos(2*PI/l),sin(2*PI/l));
        if(invflag)
            wi=cp(cos(2*PI/l),-sin(2*PI/l));
        for(cp *p=a; p!=a+n; p+=l)
        {
            cp w=cp(1,0);
            for(int i=0; i<m; ++i)
            {
                cp t=w*p[i+m];
                p[i+m]=p[i]-t;
                p[i]=p[i]+t;
                w=w*wi;
            }
        }
    }
    if(invflag)
    {
        for(int i=0; i<n; ++i)
            a[i].x/=n,a[i].y/=n;
    }
}
int n,m;
cp a[MAXN],b[MAXN];
int main()
{
    n=read(),m=read();
    ++n,++m;
    for(int i=0; i<n; ++i)
        a[i]=cp((double)read(),0);
    for(int i=0; i<m; ++i)
        b[i]=cp((double)read(),0);
    int N=1,lim=0;
    while(N<n+m-1)
        N<<=1,++lim;
    init(N,lim);
    FFT(a,N,false);
    FFT(b,N,false);
    for(int i=0; i<N; ++i)
        a[i]=a[i]*b[i];
    FFT(a,N,true);
    for(int i=0; i<n+m-1; ++i)
        printf("%d ",(int)(a[i].x+0.5));
    return 0;
}

\(NTT\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN=4e6+10;
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(; !isdigit(ch); ch=getchar())
        if(ch=='-')
            pos=0;
    for(; isdigit(ch); ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
const int P=998244353,G=3;
int add(int a,int b)
{
    return (a + b) % P;
}
int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=mul(res,a);
        a=mul(a,a);
        b>>=1;
    }
    return res;
}
int inv(int x)
{
    return fpow(x,P-2);
}
int rev[MAXN];
void init(int n,int lim)
{
    for(int i=0; i<n; ++i)
    {
        for(int j=0; j<lim; ++j)
            if((i>>j)&1)
                rev[i]|=1<<(lim-j-1);
    }
}
void NTT(int *a,int n,bool invflag)
{
    for(int i=0; i<n; ++i)
    {
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    }
    for(int l=2; l<=n; l<<=1)
    {
        int gi=fpow(G,(P-1)/l);
        if(invflag)
            gi=inv(gi);
        int m=l>>1;
        for(int *p=a;p!=a+n;p+=l)
        {
            int g=1;
            for(int i=0; i<m; ++i)
            {
                int t=mul(g,p[i+m]);
                p[i+m]=add(p[i],P-t);
                p[i]=add(p[i],t);
                g=mul(g,gi);
            }
        }
    }
    if(invflag)
    {
        int Invn=inv(n);
        for(int i=0; i<n; ++i)
            a[i]=mul(a[i],Invn);
    }
}
int n,m;
int a[MAXN],b[MAXN];
int main()
{
    n=read(),m=read();
    ++n,++m;
    for(int i=0; i<n; ++i)
        a[i]=read();
    for(int i=0; i<m; ++i)
        b[i]=read();
    int N=1,lim=0;
    while(N<n+m-1)
        N<<=1,++lim;
    init(N,lim);
    NTT(a,N,false);
    NTT(b,N,false);
    for(int i=0; i<N; ++i)
        a[i]=mul(a[i],b[i]);
    NTT(a,N,true);
    for(int i=0; i<n+m-1; ++i)
        printf("%d ",a[i]);
    return 0;
}

\(FWT\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int P=998244353,inv2=(P+1)>>1;
inline int add(int a,int b)
{
    return (a + b) % P;
}
inline int mul(int a,int b)
{
    return 1LL * a * b % P;
}
void FWT(int *a,int n,int op)
{
    for(int l=2;l<=n;l<<=1)
    {
        int m=l>>1;
        for(int *p=a;p!=a+n;p+=l)
            for(int i=0;i<m;++i)
            {
                int x0=p[i],x1=p[i+m];
                if(op==1)//or
                    p[i]=x0,p[i+m]=add(x0,x1);
                else if(op==2)//and
                    p[i]=add(x0,x1),p[i+m]=x1;
                else//xor
                    p[i]=add(x0,x1),p[i+m]=add(x0,P-x1);
            }
    }
}
void IFWT(int *a,int n,int op)
{
    for(int l=2;l<=n;l<<=1)
    {
        int m=l>>1;
        for(int *p=a;p!=a+n;p+=l)
            for(int i=0;i<m;++i)
            {
                int x0=p[i],x1=p[i+m];
                if(op==1)
                    p[i]=x0,p[i+m]=add(x1,P-x0);
                else if(op==2)
                    p[i]=add(x0,P-x1),p[i+m]=x1;
                else
                    p[i]=mul(add(x0,x1),inv2),p[i+m]=mul(add(x0,P-x1),inv2);
            }
    }
}
const int MAXN=(1<<17)+10;
int a[MAXN],b[MAXN],c[MAXN];
int main()
{
    int n=read();
    n=1<<n;
    for(int i=0;i<n;++i)
        a[i]=read();
    for(int i=0;i<n;++i)
        b[i]=read();
    for(int op=1;op<=3;++op)
    {
        FWT(a,n,op);
        FWT(b,n,op);
        for(int i=0;i<n;++i)
            c[i]=mul(a[i],b[i]);
        IFWT(a,n,op);
        IFWT(b,n,op);
        IFWT(c,n,op);
        for(int i=0;i<n;++i)
            printf("%d ",c[i]);
        puts("");
    }
    return 0;
}

三模数 \(NTT\)

  • 取三个具有 \(P=p\cdot 2^k+1\) 形式的模数,在每个模意义下分别求解,最后用 \(CRT​\) 合并.这样做要求最终答案不超过三个模数之积.

拆系数 \(FFT\)

  • 对任意模数 \(P\) ,记 \(m=\sqrt P\).那么把每个系数写成 \(a\times m+b,a,b<m\) 的形式,然后乘法分配律分别做,这样每个系数都不会超过 \(P\) ,最后再合并.

分治 \(NTT/FFT\)

  • 现在要算这样一个形式的卷积:
    \[ f_i=\sum_{j=1}^{i}f_{i-j}\cdot g_j \]

  • 给出初始值 \(f_0\) 以及 \(g\) 的所有值,求 \(f\) 的所有项.
  • 如果每次直接做 \(NTT/FFT\) ,复杂度显然为 \(O(n^2logn)\) ,爆炸.
  • 考虑一个像 \(cdq\) 分治的东西,即算左边,再算左边对右边的贡献,再算右边,长度为 \(1\) 时返回.
  • 若当前计算区间 \([l,r)\) ,就把 \(f\) 的前 \(\frac {r-l} 2\) 项与 \(g\) 的前 \(r-l\) 项做卷积,把答案的后 \(\frac {r-l} 2\) 项加入 \(f\) 的对应位置.
  • 这样做后半段一定是对的,所以就不用关注长度的问题了.时间复杂度为 \(O(nlog^2n)\) .

    分治 \(NTT\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read()
{
    ll out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        fh=-1,jp=getchar();
    while (jp>='0'&&jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*fh;
}
const int P=998244353,G=3;
inline int add(int a,int b)
{
    return (a + b) % P;
}
inline int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=mul(res,a);
        a=mul(a,a);
        b>>=1;
    }
    return res;
}
const int MAXN=2e5+10;
int rev[MAXN],omega[MAXN],inv[MAXN];
void rev_init(int n,int lim)
{
    for(int i=0;i<n;++i)
    {
        int t=0;
        for(int j=0;j<lim;++j)
            if((i>>j)&1)
                t|=1<<(lim-j-1);
        rev[i]=t;
    }
}
void omega_init(int n)
{
    for(int l=2;l<=n;l<<=1)
    {
        omega[l]=fpow(G,(P-1)/l);
        inv[l]=fpow(omega[l],P-2);
    }
}
void NTT(int *a,int n,int lim,int invflag)
{
    for(int i=0;i<n;++i)
    {
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    }
    for(int l=2;l<=n;l<<=1)
    {
        int m=l>>1;
        int gi=omega[l];
        if(invflag)
            gi=inv[l];
        for(int *p=a;p!=a+n;p+=l)
        {
            int g=1;
            for(int i=0;i<m;++i)
            {
                int t=mul(g,p[i+m]);
                p[i+m]=add(p[i],P-t);
                p[i]=add(p[i],t);
                g=mul(g,gi);
            }
        }
    }
    if (invflag)
    {
        int invn=fpow(n,P-2);
        for(int i=0;i<n;++i)
            a[i]=mul(a[i],invn);
    }
}
int f[MAXN],g[MAXN],a[MAXN],b[MAXN];
void solve(int l,int r,int lim)//[l,r)
{
    if(lim<=0)
        return;
    int mid=(l+r)>>1,len=r-l;
    solve(l,mid,lim-1);
    rev_init(len,lim);
    for(int i=0;i<len/2;++i)
        a[i]=f[l+i];
    for(int i=len/2;i<len;++i)
        a[i]=0;
    for(int i=0;i<len;++i)
        b[i]=g[i];
    NTT(a,len,lim,false);
    NTT(b,len,lim,false);
    for(int i=0;i<len;++i)
        a[i]=mul(a[i],b[i]);
    NTT(a,len,lim,true);
    for(int i=len/2;i<len;++i)
        f[i+l]=add(f[i+l],a[i]);
    solve(mid,r,lim-1);
}
int main()
{
    int n=read();
    f[0]=1;
    for(int i=1;i<n;++i)
        g[i]=read();
    int N=1,lim=0;
    while(N<n)
        N<<=1,++lim;
    omega_init(N);
    solve(0,N,lim); 
    for(int i=0;i<n;++i)
        printf("%d ",f[i]);
    puts("");
    return 0;
}

多项式求逆

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int out=0,sgn=1;
    char jp=getchar();
    while(jp!='-' && (jp<'0' || jp>'9'))
        jp=getchar();
    if(jp=='-')
        sgn=-1,jp=getchar();
    while(jp>='0' && jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
    return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=mul(res,a);
        a=mul(a,a);
        b>>=1;
    }
    return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
    for(int i=0;i<n;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    for(int l=2; l<=n; l<<=1)
    {
        omega[l]=fpow(G,(P-1)/l);
        inv[l]=fpow(omega[l],P-2);
    }
    curn=n;
}
void DFT(int *a,int n,bool invflag)
{
    if(curn!=n)
        init(n);
    for(int i=0; i<n; ++i)
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    for(int l=2; l<=n; l<<=1)
    {
        int m=(l>>1);
        int gi=omega[l];
        if(invflag)
            gi=inv[l];
        for(int *p=a; p!=a+n; p+=l)
        {
            int g=1;
            for(int i=0; i<m; ++i)
            {
                int t=mul(g,p[i+m]);
                p[i+m]=add(p[i],P-t);
                p[i]=add(p[i],t);
                g=mul(g,gi);
            }
        }
    }
    if(invflag)
    {
        int invn=fpow(n,P-2);
        for(int i=0; i<n; ++i)
            a[i]=mul(a[i],invn);
    }
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
    int lenC=lenA+lenB-1,n=1;
    while(n<lenC)
        n<<=1;
    for(int i=0;i<lenA;++i)
        a[i]=A[i];
    for(int i=lenA;i<n;++i)
        a[i]=0;
    for(int i=0;i<lenB;++i)
        b[i]=B[i];
    for(int i=lenB;i<n;++i)
        b[i]=0;
    DFT(a,n,false);
    DFT(b,n,false);
    for(int i=0; i<n; ++i)
        C[i]=mul(a[i],b[i]);
    DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
    B[0]=fpow(A[0],P-2);
    int k=0;
    for(int i=2;i<=n;i<<=1)
    {
        ++k;
        NTT(A,B,tmp,i,i);
        NTT(tmp,B,tmp,i,i);
        for(int j=0;j<i;++j)
            B[j]=add(mul(2,B[j]),P-tmp[j]);
    }
}
int poly[MAXN],invpoly[MAXN];
int main()
{
    int n=read();
    for(int i=0;i<n;++i)
        poly[i]=read();
    int N=1,lim=0;
    while((1<<lim)<n)
        ++lim,N<<=1;
    poly_inverse(poly,invpoly,N);
    for(int i=0;i<n;++i)
        printf("%d ",invpoly[i]);
    puts("");
    return 0;
}

多项式除法/多项式取模

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int out=0,sgn=1;
    char jp=getchar();
    while(jp!='-' && (jp<'0' || jp>'9'))
        jp=getchar();
    if(jp=='-')
        sgn=-1,jp=getchar();
    while(jp>='0' && jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
    return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=mul(res,a);
        a=mul(a,a);
        b>>=1;
    }
    return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
    for(int i=0;i<n;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    for(int l=2; l<=n; l<<=1)
    {
        omega[l]=fpow(G,(P-1)/l);
        inv[l]=fpow(omega[l],P-2);
    }
    curn=n;
}
void DFT(int *a,int n,bool invflag)
{
    if(curn!=n)
        init(n);
    for(int i=0; i<n; ++i)
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    for(int l=2; l<=n; l<<=1)
    {
        int m=(l>>1);
        int gi=omega[l];
        if(invflag)
            gi=inv[l];
        for(int *p=a; p!=a+n; p+=l)
        {
            int g=1;
            for(int i=0; i<m; ++i)
            {
                int t=mul(g,p[i+m]);
                p[i+m]=add(p[i],P-t);
                p[i]=add(p[i],t);
                g=mul(g,gi);
            }
        }
    }
    if(invflag)
    {
        int invn=fpow(n,P-2);
        for(int i=0; i<n; ++i)
            a[i]=mul(a[i],invn);
    }
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
    int lenC=lenA+lenB-1,n=1;
    while(n<lenC)
        n<<=1;
    for(int i=0;i<lenA;++i)
        a[i]=A[i];
    for(int i=lenA;i<n;++i)
        a[i]=0;
    for(int i=0;i<lenB;++i)
        b[i]=B[i];
    for(int i=lenB;i<n;++i)
        b[i]=0;
    DFT(a,n,false);
    DFT(b,n,false);
    for(int i=0; i<n; ++i)
        C[i]=mul(a[i],b[i]);
    DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
    for(int i=0;i<2*n;++i)
        B[i]=0;
    B[0]=fpow(A[0],P-2);
    int k=0;
    for(int i=2;i<=n;i<<=1)
    {
        ++k;
        NTT(A,B,tmp,i,i);
        NTT(tmp,B,tmp,i,i);
        for(int j=0;j<i;++j)
            B[j]=add(mul(2,B[j]),P-tmp[j]);
    }
}
void poly_rev(int *A,int n)//n->最高项次数 
{
    for(int i=0;i<n-i;++i)
        swap(A[i],A[n-i]);
}
int InvB[MAXN];
int ModA[MAXN],ModB[MAXN];
void poly_division(int *A,int *B,int *D,int *R,int n,int m)
{
    poly_rev(A,n);
    poly_rev(B,m);
    for(int i=0;i<n-m+1;++i)
        ModA[i]=A[i],ModB[i]=B[i];
    int N=1;
    while(N<n-m+1)
        N<<=1;
    poly_inverse(ModB,InvB,N);
    for(int i=n-m+1;i<N;++i)
        InvB[i]=0;
    NTT(ModA,InvB,D,n-m+1,n-m+1);
    poly_rev(D,n-m);
    poly_rev(A,n);
    poly_rev(B,m);
    NTT(B,D,R,m,n-m+1);
    for(int i=0;i<n;++i)
        R[i]=add(A[i],P-R[i]);
}
int A[MAXN],B[MAXN],D[MAXN],R[MAXN];
int main()
{
    int n=read(),m=read();
    for(int i=0;i<=n;++i)
        A[i]=read();
    for(int i=0;i<=m;++i)
        B[i]=read();
    poly_division(A,B,D,R,n,m);
    for(int i=0;i<n-m+1;++i)
        printf("%d ",D[i]);
    puts("");
    for(int i=0;i<m;++i)
        printf("%d ",R[i]);
    puts("");
    return 0;
}

多项式 \(\ln\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int out=0,sgn=1;
    char jp=getchar();
    while(jp!='-' && (jp<'0' || jp>'9'))
        jp=getchar();
    if(jp=='-')
        sgn=-1,jp=getchar();
    while(jp>='0' && jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
    return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=mul(res,a);
        a=mul(a,a);
        b>>=1;
    }
    return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
    for(int i=0;i<n;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    for(int l=2; l<=n; l<<=1)
    {
        omega[l]=fpow(G,(P-1)/l);
        inv[l]=fpow(omega[l],P-2);
    }
    curn=n;
}
void DFT(int *a,int n,bool invflag)
{
    if(curn!=n)
        init(n);
    for(int i=0; i<n; ++i)
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    for(int l=2; l<=n; l<<=1)
    {
        int m=(l>>1);
        int gi=omega[l];
        if(invflag)
            gi=inv[l];
        for(int *p=a; p!=a+n; p+=l)
        {
            int g=1;
            for(int i=0; i<m; ++i)
            {
                int t=mul(g,p[i+m]);
                p[i+m]=add(p[i],P-t);
                p[i]=add(p[i],t);
                g=mul(g,gi);
            }
        }
    }
    if(invflag)
    {
        int invn=fpow(n,P-2);
        for(int i=0; i<n; ++i)
            a[i]=mul(a[i],invn);
    }
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
    int lenC=lenA+lenB-1,n=1;
    while(n<lenC)
        n<<=1;
    for(int i=0;i<lenA;++i)
        a[i]=A[i];
    for(int i=lenA;i<n;++i)
        a[i]=0;
    for(int i=0;i<lenB;++i)
        b[i]=B[i];
    for(int i=lenB;i<n;++i)
        b[i]=0;
    DFT(a,n,false);
    DFT(b,n,false);
    for(int i=0; i<n; ++i)
        C[i]=mul(a[i],b[i]);
    DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
    for(int i=0;i<2*n;++i)
        B[i]=0;
    B[0]=fpow(A[0],P-2);
    int k=0;
    for(int i=2;i<=n;i<<=1)
    {
        ++k;
        NTT(A,B,tmp,i,i);
        NTT(tmp,B,tmp,i,i);
        for(int j=0;j<i;++j)
            B[j]=add(mul(2,B[j]),P-tmp[j]);
    }
}
void poly_diff(int *A,int n)
{
    for(int i=0;i<n-1;++i)
        A[i]=mul(A[i+1],i+1);
}
void poly_int(int *A,int n)
{
    for(int i=n;i>=1;--i)
        A[i]=mul(A[i-1],fpow(i,P-2));
}
int InvA[MAXN];
void ln(int *A,int *B,int n)
{
    poly_inverse(A,InvA,n);
    poly_diff(A,n);
    NTT(A,InvA,B,n,n);
    poly_int(B,n);
    B[0]=0;
}
int A[MAXN],B[MAXN];
int main()
{
    int n=read();
    int N=1;
    while(N<n)
        N<<=1;
    for(int i=0;i<n;++i)
        A[i]=read();
    ln(A,B,N);
    for(int i=0;i<n;++i)
        printf("%d ",B[i]);
    puts("");
    return 0;
}

多项式 \(\exp\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
    int out=0,sgn=1;
    char jp=getchar();
    while(jp!='-' && (jp<'0' || jp>'9'))
        jp=getchar();
    if(jp=='-')
        sgn=-1,jp=getchar();
    while(jp>='0' && jp<='9')
        out=out*10+jp-'0',jp=getchar();
    return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
    return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=mul(res,a);
        a=mul(a,a);
        b>>=1;
    }
    return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
    for(int i=0;i<n;++i)
        rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
    for(int l=2; l<=n; l<<=1)
    {
        omega[l]=fpow(G,(P-1)/l);
        inv[l]=fpow(omega[l],P-2);
    }
    curn=n;
}
void DFT(int *a,int n,bool invflag)
{
    if(curn!=n)
        init(n);
    for(int i=0; i<n; ++i)
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    for(int l=2; l<=n; l<<=1)
    {
        int m=(l>>1);
        int gi=omega[l];
        if(invflag)
            gi=inv[l];
        for(int *p=a; p!=a+n; p+=l)
        {
            int g=1;
            for(int i=0; i<m; ++i)
            {
                int t=mul(g,p[i+m]);
                p[i+m]=add(p[i],P-t);
                p[i]=add(p[i],t);
                g=mul(g,gi);
            }
        }
    }
    if(invflag)
    {
        int invn=fpow(n,P-2);
        for(int i=0; i<n; ++i)
            a[i]=mul(a[i],invn);
    }
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
    int lenC=lenA+lenB-1,n=1;
    while(n<lenC)
        n<<=1;
    for(int i=0;i<lenA;++i)
        a[i]=A[i];
    for(int i=lenA;i<n;++i)
        a[i]=0;
    for(int i=0;i<lenB;++i)
        b[i]=B[i];
    for(int i=lenB;i<n;++i)
        b[i]=0;
    DFT(a,n,false);
    DFT(b,n,false);
    for(int i=0; i<n; ++i)
        C[i]=mul(a[i],b[i]);
    DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
    for(int i=0;i<2*n;++i)
        B[i]=0;
    B[0]=fpow(A[0],P-2);
    int k=0;
    for(int i=2;i<=n;i<<=1)
    {
        ++k;
        NTT(A,B,tmp,i,i);
        NTT(tmp,B,tmp,i,i);
        for(int j=0;j<i;++j)
            B[j]=add(mul(2,B[j]),P-tmp[j]);
    }
}
void poly_diff(int *A,int n)
{
    for(int i=0;i<n-1;++i)
        A[i]=mul(A[i+1],i+1);
}
void poly_int(int *A,int n)
{
    for(int i=n;i>=1;--i)
        A[i]=mul(A[i-1],fpow(i,P-2));
}
int InvA[MAXN],tmpA[MAXN];
void poly_ln(int *A,int *B,int n)
{
    for(int i=0;i<n;++i)
        tmpA[i]=A[i];
    poly_inverse(tmpA,InvA,n);
    poly_diff(tmpA,n);
    NTT(tmpA,InvA,B,n,n);
    poly_int(B,n);
    B[0]=0;
    for(int i=0;i<n;++i)
        tmpA[i]=0;
}
int lnB[MAXN];
void poly_exp(int *A,int *B,int n)
{
    if(n==1)
    {
        B[0]=1;
        return;
    }
    poly_exp(A,B,n>>1);
    for(int i=0;i<n;++i)
        lnB[i]=0;
    poly_ln(B,lnB,n);
    for(int i=0;i<n;++i)
        lnB[i]=add(A[i],P-lnB[i]);
    lnB[0]=add(lnB[0],1);
    NTT(B,lnB,B,n>>1,n);
    for(int i=n;i<(n+(n>>1));++i)
        B[i]=0;     
}
int A[MAXN],B[MAXN];
int main()
{
    int n=read();
    for(int i=0;i<n;++i)
        A[i]=read();
    int N=1;
    while(N<n)
        N<<=1;
    poly_exp(A,B,N);
    for(int i=0;i<n;++i)
        printf("%d ",B[i]);
    puts("");
    return 0;
}

转载于:https://www.cnblogs.com/jklover/p/10666102.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值