分治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 模板的主要内容,如果未能解决你的问题,请参考以下文章

分治FFT/NTT

分治FFT/NTT

分治FFT

FFT/NTT及多项式运算模板

多项式FFT/NTT模板(含乘法/逆元/log/exp/求导/积分/快速幂)

fft,ntt,fwt