G43 快速数论变换 NTT算法

视频链接:https://www.bilibili.com/video/BV1a3411Z7vL/

   Luogu P3803 【模板】多项式乘法(FFT)

// 递归版 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]);    
}

 

posted @ 2023-01-02 23:35  董晓  阅读(545)  评论(0编辑  收藏  举报