任意模數 NTT
阿新 • • 發佈:2020-09-12
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll MAXN=1<<21,MOD1=998244353,MOD2=1004535809,MOD3=469762049; inline ll fpow(ll a,ll x,ll mod) { ll ans=1; for(;x;x>>=1,a=a*a%mod) if(x&1) ans=ans*a%mod; return ans; } inline ll inv(ll a,ll mod) { return fpow(a,mod-2,mod); } ll L,Rev[MAXN],invL1,invL2,invL3; inline void preNTT(){ Rev[1]=L>>1; for(int i=2;i<L;i++) Rev[i]=(Rev[i>>1]>>1)|Rev[i&1]; invL1=inv(L,MOD1); invL2=inv(L,MOD2); invL3=inv(L,MOD3); } inline void NTT(int f[MAXN][4],ll op){ ll g1=(op==1?3:inv(3,MOD1)),g2=(op==1?3:inv(3,MOD2)),g3=(op==1?3:inv(3,MOD3)); for(int i=1;i<L;i++) if(i<Rev[i]) for(int j=1;j<=3;j++) swap(f[i][j],f[Rev[i]][j]); for(int bas=2,mid=1,lb=1;bas<=L;bas<<=1,mid<<=1,lb++) for(int l=0,omega1=fpow(g1,MOD1>>lb,MOD1),omega2=fpow(g2,MOD2>>lb,MOD2),omega3=fpow(g3,MOD3>>lb,MOD3);l<L;l+=bas) for(int k=l,buf1=1,buf2=1,buf3=1,tmp1,tmp2,tmp3; tmp1=1ll*buf1*f[k+mid][1]%MOD1,tmp2=1ll*buf2*f[k+mid][2]%MOD2,tmp3=1ll*buf3*f[k+mid][3]%MOD3,k<mid+l; k++,buf1=1ll*buf1*omega1%MOD1,buf2=1ll*buf2*omega2%MOD2,buf3=1ll*buf3*omega3%MOD3) f[k+mid][1]=(0ll+f[k][1]-tmp1)%MOD1,f[k][1]=(0ll+f[k][1]+tmp1)%MOD1, f[k+mid][2]=(0ll+f[k][2]-tmp2)%MOD2,f[k][2]=(0ll+f[k][2]+tmp2)%MOD2, f[k+mid][3]=(0ll+f[k][3]-tmp3)%MOD3,f[k][3]=(0ll+f[k][3]+tmp3)%MOD3; if(op==1){ for(int i=0;i<L;i++) f[i][1]=(0ll+f[i][1]+MOD1)%MOD1,f[i][2]=(0ll+f[i][2]+MOD2)%MOD2,f[i][3]=(0ll+f[i][3]+MOD3)%MOD3; } else{ for(int i=0;i<L;i++) f[i][1]=(0ll+f[i][1]+MOD1)*invL1%MOD1,f[i][2]=(0ll+f[i][2]+MOD2)*invL2%MOD2,f[i][3]=(0ll+f[i][3]+MOD3)*invL3%MOD3; } } inline void mul(int f[MAXN][4],int g[MAXN][4],int h[MAXN][4],int N){ static int p[MAXN][4],q[MAXN][4]; L=1; while(L<(N<<1)) L<<=1; preNTT(); for(int i=0;i<L;i++) p[i][1]=f[i][1],q[i][1]=g[i][1], p[i][2]=f[i][2],q[i][2]=g[i][2], p[i][3]=f[i][3],q[i][3]=g[i][3]; NTT(p,1); NTT(q,1); for(int i=0;i<L;i++) h[i][1]=1ll*p[i][1]*q[i][1]%MOD1, h[i][2]=1ll*p[i][2]*q[i][2]%MOD2, h[i][3]=1ll*p[i][3]*q[i][3]%MOD3; NTT(h,-1); } inline int crt(ll a1,ll m1,ll a2,ll m2,ll a3,ll m3,ll p){ __int128 mod=1,sum=0; mod=mod*m1*m2*m3; sum+=mod/m1*inv(mod/m1%m1,m1)*a1; sum+=mod/m2*inv(mod/m2%m2,m2)*a2; sum+=mod/m3*inv(mod/m3%m3,m3)*a3; return sum%mod%p; } int F[MAXN][4],G[MAXN][4],H[MAXN][4],N,M,P; inline void work(){ cin>>N>>M>>P; for(int i=0;i<=N;i++) cin>>F[i][0],F[i][3]=F[i][2]=F[i][1]=F[i][0]; for(int i=0;i<=M;i++) cin>>G[i][0],G[i][3]=G[i][2]=G[i][1]=G[i][0]; mul(F,G,H,N+M+2); for(int i=0;i<L;i++) H[i][0]=crt(H[i][1],MOD1,H[i][2],MOD2,H[i][3],MOD3,P); } int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); work(); for(int i=0;i<=N+M;i++) cout<<H[i][0]<<" "; cout<<endl; return 0; }