$\text{O}(n \log n)$ 多项式运算
原本的板子有点拉胯,贴个少一些操作的快速板子(然而有些清空和封装没做好)
#include<cstdio> #include<cctype> #include<vector> #include<algorithm> #define maxn 3003003 const int G=3,mod=998244353; template<class T> inline T read(){ T r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } inline long long qpow(long long a,int b){ long long ans=1; for(;b;b>>=1){ if(b&1)(ans*=a)%=mod; (a*=a)%=mod; } return ans; } namespace Poly{//Need Init int Lst,g[maxn],rev[maxn]; long long frac[maxn],invf[maxn],inv[maxn]; inline void Add(int &x,int y){ x+=y-mod,x+=(x>>31)&mod; } inline void Sub(int &x,int y){ x-=y,x+=(x>>31)&mod; } inline void clr(int *f,int n){ for(int i=0;i<n;i++)f[i]=0; } inline void cpy(int *f,int *g,int n){ for(int i=0;i<n;i++)f[i]=g[i]; } inline void T(int n,int *f){ std::reverse(f,f+n); } inline void Der(int n,int *f){ for(int i=0;i<n-1;i++) f[i]=f[i+1]*(i+1ll)%mod; f[n-1]=0; } inline void Int(int n,int *f){ for(int i=n-1;i;i--) f[i]=f[i-1]*inv[i]%mod; f[0]=0; } inline void init(int n){ frac[0]=1; for(int i=1;i<n;i++) frac[i]=frac[i-1]*i%mod; invf[n-1]=qpow(frac[n-1],mod-2); for(int i=n-1;i;i--){ invf[i-1]=invf[i]*i%mod; inv[i]=invf[i]*frac[i-1]%mod; } int N=1; for(;N<n;N<<=1); for(int i=1;i<N;i<<=1){ g[i]=1; int p=i<<1; long long x=qpow(G,(mod-1)/p); for(int j=i+1;j<p;j++) g[j]=g[j-1]*x%mod; } } inline void init_rev(int N){ if(N==Lst)return; for(int i=1;i<N;i++) rev[i]=(rev[i>>1]>>1)|(i&1?N>>1:0); Lst=N; } inline void NTT(int N,int *f,bool opt){ static unsigned long long A[maxn]; for(int i=0;i<N;i++)A[i]=f[rev[i]]; for(int i=1;i<N;i<<=1) for(int j=0,p=i<<1;j<N;j+=p) for(int k=0;k<i;k++){ int l=j|k,r=i|l; int val=A[r]*g[i|k]%mod; A[r]=A[l]+mod-val,A[l]+=val; } if(!opt){ for(int i=0;i<N;i++) f[i]=A[i]%mod; return; } int invn=mod-(mod-1)/N; f[0]=A[0]%mod*invn%mod; for(int i=1;i<N;i++) f[i]=A[N-i]%mod*invn%mod; } int A[maxn],B[maxn],C[maxn],D[maxn]; inline void Inv(int N,int *f,int *invf){ invf[0]=qpow(f[0],mod-2); for(int len=2;len<=N;len<<=1){ init_rev(len); cpy(A,f,len); cpy(B,invf,len>>1); NTT(len,A,0),NTT(len,B,0); for(int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod,B[i]=0; NTT(len,A,1),clr(A,len>>1),NTT(len,A,0); cpy(B,invf,len>>1),NTT(len,B,0); for(int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod,B[i]=0; NTT(len,A,1),clr(A,len>>1); for(int i=len>>1;i<len;i++) invf[i]=mod-A[i],A[i]=0; } } inline void Ln(int N,int *f,int *lnf){ Inv(N,f,lnf); cpy(B,f,N),Der(N,B); init_rev(N<<=1); NTT(N,lnf,0),NTT(N,B,0); for(int i=0;i<N;i++) lnf[i]=1ll*lnf[i]*B[i]%mod,B[i]=0; NTT(N,lnf,1),N>>=1,clr(lnf+N,N); Int(N,lnf); } inline void Exp(int N,int *f,int *expf){ expf[0]=1; for(int len=2;len<=N;len<<=1){ cpy(C,expf,len>>1),Ln(len,C,D); for(int i=0;i<len;i++) if((A[i]=f[i]+mod-D[i])>=mod)A[i]-=mod; init_rev(len),NTT(len,A,0),NTT(len,C,0); for(int i=0;i<len;i++) A[i]=1ll*A[i]*C[i]%mod,C[i]=0; NTT(len,A,1),clr(A,len>>1); for(int i=len>>1;i<len;i++) expf[i]=A[i],A[i]=0; } } template<int MAXN> struct Polyn{ int n,f[MAXN]; int& operator [](const int x){return f[x];} Polyn& operator +=(int b){ Add(f[0],b); return (*this); } Polyn& operator +=(Polyn &b){ while(n<b.n)f[n++]=0; for(int i=0;i<b.n;i++)Add(f[i],b[i]); return (*this); } Polyn& operator -=(int b){ Sub(f[0],b); return (*this); } Polyn& operator -=(Polyn &b){ while(n<b.n)f[n++]=0; for(int i=0;i<b.n;i++)Sub(f[i],b[i]); return (*this); } Polyn& operator *=(long long b){ for(int i=0;i<n;i++) f[i]=f[i]*b%mod; return (*this); } Polyn& operator *=(Polyn &b){ int N=1; for(;N<n+b.n-1;N<<=1); init_rev(N); for(int i=0;i<b.n;i++)A[i]=b[i]; NTT(N,f,0),NTT(N,A,0); for(int i=0;i<N;i++) f[i]=1ll*f[i]*A[i]%mod,A[i]=0; NTT(N,f,1),n=n+b.n-1,clr(f+n,N-n); return (*this); } Polyn operator +(int b) const{ Polyn c(*this); return c+=b; } Polyn operator +(Polyn &b) const{ Polyn c(*this); return c+=b; } Polyn operator -(int b) const{ Polyn c(*this); return c-=b; } Polyn operator -(Polyn &b) const{ Polyn c(*this); return c-=b; } Polyn operator *(long long b) const{ Polyn c(*this); return c*=b; } Polyn operator *(Polyn &b) const{ Polyn c(*this); return c*=b; } inline Polyn T(){ Polyn b(*this); std::reverse(b,b+b.n); return b; } inline Polyn Der(){ Polyn b(*this); for(int i=0;i<n-1;i++) b[i]=b[i+1]*(i+1ll)%mod; b[b.n--]=0; return b; } inline Polyn Int(){ Polyn b(*this); for(int i=b.n;i;i--) b[i]=b[i-1]*inv[i]%mod; b[0]=0,b.n++; return b; } inline Polyn Inv(int m=0){ int N=1; Polyn b(*this); for(m=!m?n:m;N<m;N<<=1); Poly::Inv(N,f,b.f),clr(b.f+m,N-m); return b; } inline Polyn Ln(int m=0){ int N=1; Polyn b(*this); for(m=!m?n:m;N<m;N<<=1); Poly::Ln(N,f,b.f),clr(b.f+m,N-m); return b; } inline Polyn Exp(int m=0){ int N=1; Polyn b(*this); for(m=!m?n:m;N<m;N<<=1); Poly::Exp(N,f,b.f),clr(b.f+m,N-m); return b; } }; } Poly::Polyn<maxn> f,g; int main(){ f.n=read<int>()+1; g.n=read<int>()+1; Poly::init(f.n+g.n-1); for(int i=0;i<f.n;i++) f[i]=read<int>(); for(int i=0;i<g.n;i++) g[i]=read<int>(); f*=g; for(int i=0;i<f.n;i++) printf("%d ",f[i]); return 0; }
贴个老板子
namespace Modsqrt{ #define ll long long ll w2; struct CP{ ll x,y; CP() {} CP(ll x,ll y):x(x),y(y) {} CP operator *(const CP &a) const{ ll X=(x*a.x+y*a.y%mod*w2)%mod; ll Y=(x*a.y+y*a.x)%mod; return CP(X,Y); } }; inline CP CP_qpow(CP a,int b){ CP ans=CP(1,0); for(;b;b>>=1){ if(b&1)ans=ans*a; a=a*a; } return ans; } inline ll modsqrt(ll x){ srand(time(0)); ll y=1ll*rand()*rand()%mod; while(qpow(w2=(y*y+mod-x)%mod,(mod-1)>>1)==1) y=1ll*rand()*rand()%mod; CP ans=CP_qpow(CP(y,1),(mod+1)>>1); return min(ans.x,mod-ans.x); } #undef ll } using namespace Modsqrt; long long inv[maxn],frac[maxn],invf[maxn]; inline void Init_Inv(int N){ frac[0]=1; for(int i=1;i<=N;i++)frac[i]=frac[i-1]*i%mod; invf[N]=qpow(frac[N],mod-2); for(int i=N;i>=1;i--)invf[i-1]=invf[i]*i%mod; for(int i=1;i<=N;i++)inv[i]=invf[i]*frac[i-1]%mod; } inline void init(int N){ Init_Inv(N); } namespace Polyn{ #define G 3 #define ll long long int lstn,rev[maxn]; long long g[2][33]; inline void cpy(int N,ll *a,ll *b){ for(int i=0;i<N;i++)a[i]=b[i]; } inline void clr(int N,ll *a){ for(int i=0;i<N;i++)a[i]=0; } inline void mve(int N,int len,ll *a){ if(!len)return; if(len>0){ for(int i=N-1;i>=len;i--)a[i]=a[i-len]; for(int i=len-1;i>=0;i--)a[i]=0; } else { len=-len; for(int i=0;i<N-len;i++)a[i]=a[i+len]; for(int i=N-len;i<N;i++)a[i]=0; } } inline void Init_G(){ g[0][23]=qpow(G,(mod-1)/(1<<23)); g[1][23]=qpow(g[0][23],mod-2); for(int i=22;i>=1;i--){ g[0][i]=g[0][i+1]*g[0][i+1]%mod; g[1][i]=g[1][i+1]*g[1][i+1]%mod; } } inline void init(int N){ if(lstn==N)return; lstn=N; for(int i=1;i<N;i++) rev[i]=(rev[(i>>1)]>>1)|(i&1?(N>>1):0); } inline void Der(int N,ll *f){ for(int i=1;i<N;i++) f[i-1]=f[i]*i%mod; f[N-1]=0; } inline void Int(int N,ll *f){ for(int i=N;i;i--) f[i]=f[i-1]*inv[i]%mod; f[0]=0; } inline void NTT(int N,ll *f,bool flg){ for(int i=1;i<N;i++) if(i<rev[i])swap(f[i],f[rev[i]]); for(int i=1,lg=1;i<N;i<<=1,lg++){ for(int p=(i<<1),j=0;j<N;j+=p){ ll ng=1; for(int k=0;k<i;k++){ ll val=ng*f[i+j+k]%mod; f[i+j+k]=(f[j+k]+mod-val)%mod; (f[j+k]+=val)%=mod; (ng*=g[flg][lg])%=mod; } } } if(!flg)return; ll invn=qpow(N,mod-2); for(int i=0;i<N;i++) (f[i]*=invn)%=mod; } inline void Mul(int n,ll *a,ll b){ for(int i=0;i<n;i++)(a[i]*=b)%=mod; } inline void Mul(int n,ll *a,ll *b,int na=-1,int nb=-1,int len=-1){ int N=1; for(;N<n;N<<=1); init(N); if(na<0)na=n; if(nb<0)nb=n; clr(N-na,a+na),clr(N-nb,b+nb); NTT(N,a,0),NTT(N,b,0); for(int i=0;i<N;i++) (a[i]*=b[i])%=mod; NTT(N,a,1); if(len<0)return; clr(N-len,a+len); } inline void Inv(int n,ll *f,ll *ans){ static ll A[maxn],B[maxn]; int N=1; for(;N<n;N<<=1); clr(N,A),clr(N,B),clr(N,ans); ans[0]=qpow(f[0],mod-2); for(int len=2;len<=N;len<<=1){ cpy(len>>1,A,ans); cpy(len,B,f); Mul(len,A,B); clr(len>>1,A); cpy(len,B,ans); Mul(len,A,B); for(int i=(len>>1);i<len;i++) ans[i]=(ans[i]*2+mod-A[i])%mod; } } inline void Sqrt(int n,ll *f,ll *ans){ static ll A[maxn],B[maxn]; int N=1; for(;N<n;N<<=1); clr(N,A),clr(N,B),clr(N,ans); ans[0]=modsqrt(f[0]); for(int len=2;len<=N;len<<=1){ Inv(len,ans,A); cpy(len,B,f); Mul((len<<1),A,B,len,len,len); for(int i=0;i<len;i++) ans[i]=(ans[i]+A[i])*inv2%mod; } clr(N-n,ans+n); } inline void Ln(int n,ll *f,ll *ans){ static ll A[maxn]; int N=1; for(;N<(n<<1);N<<=1); clr(N,A),clr(N,ans); cpy(n,ans,f); Der(n,ans); Inv(n,f,A); Mul(n+n-1,ans,A,n); Int(n,ans); } inline void Exp(int n,ll *f,ll *ans){ static ll A[maxn],B[maxn]; int N=1; for(;N<n;N<<=1); clr(N,A),clr(N,B),clr(N,ans); ans[0]=1; for(int len=2;len<=N;len<<=1){ cpy(len,B,f); B[0]++; Ln(len,ans,A); for(int i=0;i<len;i++) (B[i]+=mod-A[i])%=mod; Mul((len<<1),ans,B,len,len,len); } clr(N-n,ans+n); } inline void Pow(int n,int k,int k1,int MOD,ll *f,ll *ans){ if(n==1)cpy(n,ans,f); static ll A[maxn]; int x=0; int N=1; for(;N<n;N<<=1); clr(N,A),clr(N,ans); for(;x<n&&!f[x];x++); if(1ll*x*k1>=MOD)return; cpy(n,ans,f); mve(n,-x,ans); int m=MOD-x; if(ans[0]>1){ ll inv0=qpow(ans[0],mod-2); for(int i=0;i<n-x;i++) (ans[i]*=inv0)%=mod; } Ln(m,ans,A); Mul(m,A,k); Exp(m,A,ans); mve(MOD,x*k1,ans); if(f[x]>1)Mul(MOD,ans,qpow(f[x],k1)); } #undef ll #undef G } long long A[maxn]; struct P{ #define ll long long int n; ll f[maxn]; inline void Read(){ for(int i=0;i<n;i++) f[i]=read<ll>(); } inline void Print(){ for(int i=0;i<n;i++) printf("%lld ",f[i]); puts(""); } ll& operator [](const int &x){ return f[x]; } inline P Mod(int N){ P c; c.n=N; for(int i=0;i<N;i++) c[i]=f[i]; return c; } inline P R(){ P c; c.n=n; for(int i=0;i<n;i++) c[i]=f[n-i-1]; return c; } inline P Der(){ P c; c.n=n-1; for(int i=1;i<n;i++) c[i-1]=f[i]*i%mod; return c; } inline P Int(){ P c; c.n=n+1; for(int i=1;i<=n;i++) c[i]=f[i-1]*inv[i]%mod; c[0]=0; return c; } inline P Inv(){ P c; c.n=n; Polyn::Inv(n,f,c.f); return c; } inline P Sqrt(){ P c; c.n=n; Polyn::Sqrt(n,f,c.f); return c; } inline P Ln(){ P c; c.n=n; Polyn::Ln(n,f,c.f); return c; } inline P Exp(){ P c; c.n=n; Polyn::Exp(n,f,c.f); return c; } inline P Pow(int k,int k1,int MOD){ P c; c.n=n; Polyn::Pow(n,k,k1,MOD,f,c.f); return c; } P operator -(){ P c; c.n=n; for(int i=0;i<c.n;i++)c[i]=mod-f[i]; return c; } P operator +(const ll b){ P c; c.n=n; for(int i=0;i<c.n;i++)c[i]=f[i]; (c[0]+=b)%=mod; return c; } P operator +(P b){ P c; c.n=max(n,b.n); for(int i=0;i<c.n;i++) c[i]=(f[i]+b[i])%mod; return c; } P operator -(const ll b){ P c; c.n=n; for(int i=0;i<c.n;i++)c[i]=f[i]; (c[0]+=mod-b%mod)%=mod; return c; } P operator -(P b){ P c; c.n=max(n,b.n); for(int i=0;i<c.n;i++) c[i]=(f[i]+mod-b[i])%mod; return c; } P operator *(const ll num){ P c; c.n=n; for(int i=0;i<n;i++) c[i]=f[i]*num%mod; return c; } P operator *(P b){ P c; c.n=n+b.n-1; for(int i=0;i<n;i++)c[i]=f[i]; for(int i=0;i<b.n;i++)A[i]=b[i]; int N=1; for(;N<c.n;N<<=1); for(int i=n;i<N;i++)c[i]=0; for(int i=b.n;i<N;i++)A[i]=0; Polyn::Mul(c.n,c.f,A); return c; } #undef ll };