分治FFT/NTT 模板
Posted guapisolo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分治FFT/NTT 模板相关的知识,希望对你有一定的参考价值。
题目要我们求$f[i]=sumlimits_{j=1}^{i}f[i-j]g[j];mod;998244353$
直接上$NTT$肯定是不行的,我们不能利用尚未求得的项卷积
所以要用$CDQ$分治,先递归$[l,mid]$,然后处理$[l,mid]$对$[mid+1,r]$的影响,再递归$[mid+1,r]$
当我们处理$[l,mid]$对$[mid+1,r]$的影响时,$f[i](iin [l,mid])$的是已经求完的,所以能用$NTT$卷积
细节比较多,注意不要让$f[i](iin [mid+1,r])$进入卷积,因为这时的$f[i]$还没有求完,会让后面的答案错误,所以要另外开一个数组记录答案
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 (1<<17)+10 6 #define ll long long 7 #define dd double 8 #define inf 0x3f3f3f3f 9 using namespace std; 10 11 const ll p=998244353; 12 void exgcd(ll a,ll b,ll &x,ll &y) 13 { 14 if(!b){ x=1; y=0; return; } 15 exgcd(b,a%b,x,y); ll t=x; x=y; y=t-a/b*y; 16 } 17 ll qpow(ll x,ll y,const ll &mod) 18 { 19 ll ans=1; 20 while(y){ 21 if(y&1) ans=ans*x%mod; 22 x=x*x%mod; y>>=1; 23 }return ans; 24 } 25 int gint() 26 { 27 int ret=0,fh=1;char c=getchar(); 28 while(c<‘0‘||c>‘9‘){if(c==‘-‘)fh=-1;c=getchar();} 29 while(c>=‘0‘&&c<=‘9‘){ret=ret*10+c-‘0‘;c=getchar();} 30 return ret*fh; 31 } 32 int r[19][N1]; 33 ll A[N1],B[N1],C[N1],g[N1],f[N1],ret[N1],invl[N1],mulwn[N1],invwn[N1]; 34 void Pre(int len,int L) 35 { 36 int i,j;ll inv,invy; 37 for(j=1;j<=L;j++) for(i=0;i<(1<<j);i++) 38 r[j][i]=(r[j][i>>1]>>1)|((i&1)<<(j-1)); 39 for(i=2;i<=len;i<<=1) 40 { 41 mulwn[i]=qpow(3,(p-1)/i,p); 42 exgcd(mulwn[i],p,inv,invy); invwn[i]=(inv%p+p)%p; 43 exgcd(i,p,inv,invy); invl[i]=(inv%p+p)%p; 44 } 45 } 46 void NTT(ll *s,int len,int type,int L) 47 { 48 int i,j,k,inv; ll w,wn,t; 49 for(i=0;i<len;i++) 50 if(i<r[L][i]) swap(s[i],s[r[L][i]]); 51 for(k=2;k<=len;k<<=1) 52 { 53 wn=type>0?mulwn[k]:invwn[k]; 54 for(i=0;i<len;i+=k) 55 { 56 for(j=0,w=1;j<(k>>1);j++,w=w*wn%p) 57 { 58 t=w*s[i+j+(k>>1)]%p; 59 s[i+j+(k>>1)]=(s[i+j]-t+p)%p; 60 s[i+j]=(s[i+j]+t)%p; 61 } 62 } 63 } 64 if(type==-1) 65 for(i=0;i<len;i++) 66 s[i]=s[i]*invl[len]%p; 67 } 68 void NTT_Main(int len,int L) 69 { 70 NTT(A,len,1,L); NTT(B,len,1,L); 71 for(int i=0;i<len;i++) C[i]=A[i]*B[i]%p; 72 NTT(C,len,-1,L); 73 } 74 ll de(int x) 75 { 76 ll ans=0; 77 for(int i=1;i<=x;i++) 78 (ans+=g[i]*f[x-i]%p)%=p; 79 return ans; 80 } 81 int debug; 82 void CDQ(int l,int r,int L) 83 { 84 if(l==r){ ret[l]=f[l]; return; } 85 int mid=(l+r)>>1,i; 86 CDQ(l,mid,L-1); 87 if(l==0&&r==7) 88 debug=1; 89 for(i=l;i<=r;i++) A[i-l]=ret[i],B[i-l]=g[i-l]; 90 NTT_Main(r-l+1,L); 91 for(i=mid+1;i<=r;i++) (f[i]+=C[i-l])%=p; 92 CDQ(mid+1,r,L-1); 93 } 94 95 int n,m,len,L; 96 int main() 97 { 98 freopen("t2.in","r",stdin); 99 scanf("%d",&n); int i; f[0]=1; 100 for(i=1;i<n;i++) g[i]=gint(); 101 for(len=1,L=0;len<n;len<<=1,L++); 102 Pre(len,L); 103 CDQ(0,len-1,L); 104 for(i=0;i<n;i++) printf("%lld ",f[i]); 105 puts(""); 106 return 0; 107 }
以上是关于分治FFT/NTT 模板的主要内容,如果未能解决你的问题,请参考以下文章