G43 快速数论变换 NTT算法
视频链接:https://www.bilibili.com/video/BV1a3411Z7vL/
// 递归版 3.2s #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define LL long long using namespace std; const int N=4e6; const int g=3,P=998244353; int n,m,gi,ni; LL A[N],B[N]; LL qpow(LL a,LL b){ LL ans=1; for(;b; a=a*a%P,b>>=1) if(b&1) ans=ans*a%P; return ans; } void NTT(LL A[],int n,int op){ if(n==1) return; LL A1[n/2],A2[n/2]; for(int i=0;i<n/2;++i) A1[i]=A[i*2], A2[i]=A[i*2+1]; NTT(A1,n/2,op); NTT(A2,n/2,op); LL g1=qpow(op==1?g:gi,(P-1)/n); LL gk=1; for(int i=0;i<n/2;++i){ A[i]=(A1[i]+A2[i]*gk)%P; A[i+n/2]=(A1[i]-A2[i]*gk%P+P)%P; gk=gk*g1%P; } } int main (){ scanf("%d%d",&n,&m); for(int i=0;i<=n;++i)scanf("%lld",&A[i]); for(int i=0;i<=m;++i)scanf("%lld",&B[i]); for(m=n+m,n=1; n<=m; n<<=1); gi=qpow(g,P-2); ni=qpow(n,P-2); NTT(A,n,1); NTT(B,n,1); for(int i=0;i<n;++i)A[i]=A[i]*B[i]%P; NTT(A,n,-1); for(int i=0;i<=m;++i) printf("%d ",A[i]*ni%P); }
// 迭代版 1.5s #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #define LL long long using namespace std; const int N=4e6; const int g=3,P=998244353; int n,m,R[N],gi,ni; LL A[N],B[N]; LL qpow(LL a,LL b){ LL ans=1; for(;b; a=a*a%P,b>>=1) if(b&1) ans=ans*a%P; return ans; } void NTT(LL A[],int n,int op){ for(int i=0; i<n; ++i) R[i]=R[i/2]/2+((i&1)?n/2:0); for(int i=0; i<n; ++i) if(i<R[i]) swap(A[i],A[R[i]]); for(int i=2; i<=n; i<<=1){ LL g1=qpow(op==1?g:gi,(P-1)/i); for(int j=0; j<n; j+=i){ LL gk=1; for(int k=j; k<j+i/2; ++k){ LL x=A[k], y=gk*A[k+i/2]%P; A[k]=(x+y)%P;A[k+i/2]=(x-y+P)%P; gk=gk*g1%P; } } } } int main(){ scanf("%d%d",&n,&m); for(int i=0;i<=n;++i)scanf("%lld",A+i); for(int i=0;i<=m;++i)scanf("%lld",B+i); for(m=n+m,n=1; n<=m; n<<=1); gi=qpow(g,P-2); ni=qpow(n,P-2); NTT(A,n,1); NTT(B,n,1); for(int i=0;i<n;++i)A[i]=A[i]*B[i]%P; NTT(A,n,-1); for(int i=0;i<=m;++i) printf("%d ",A[i]*ni%P); }
Luogu P1919 【模板】A*B Problem 升级版
// 迭代版 4.9s #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #define LL long long using namespace std; const int N=3e6; const int g=3,P=998244353; int n,m,gi,ni,R[N],ans[N]; LL A[N],B[N]; char s1[N], s2[N]; LL qpow(LL a,LL b){ LL ans=1; for(;b; a=a*a%P,b>>=1) if(b&1) ans=ans*a%P; return ans; } void NTT(LL A[],int n,int op){ for(int i=0; i<n; ++i) R[i]=R[i/2]/2+((i&1)?n/2:0); for(int i=0; i<n; ++i) if(i<R[i]) swap(A[i],A[R[i]]); for(int i=2; i<=n; i<<=1){ LL g1=qpow(op==1?g:gi,(P-1)/i); for(int j=0; j<n; j+=i){ LL gk=1; for(int k=j; k<j+i/2; ++k){ LL x=A[k], y=gk*A[k+i/2]%P; A[k]=(x+y)%P;A[k+i/2]=(x-y+P)%P; gk=gk*g1%P; } } } } int main (){ scanf("%s%s", s1, s2); int n=strlen(s1)-1, m=strlen(s2)-1; for(int i=0; i<=n; i++)A[i]=s1[n-i]-'0'; for(int i=0; i<=m; i++)B[i]=s2[m-i]-'0'; for(m=n+m,n=1; n<=m; n<<=1); gi=qpow(g,P-2); ni=qpow(n,P-2); NTT(A,n,1); NTT(B,n,1); for(int i=0;i<n;++i)A[i]=A[i]*B[i]%P; NTT(A,n,-1); for(int i=0;i<=m;++i)A[i]=A[i]*ni%P; int k=0; for(int i=0, t=0; i<n||t; i++) t+=A[i], ans[k++]=t%10, t/=10; while(k>1 && !ans[k-1]) k--; for(int i=k-1;i>=0;i--)printf("%d", ans[i]); }