分治FFT
Posted nofind
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分治FFT相关的知识,希望对你有一定的参考价值。
一、处理的问题
给出多项式(g[0...n]),求出(f[0...n])满足(f_i=sumlimits_{j=1}^if_{i-j}g_j),边界(f_0=1)。
我们发现这是个卷积的形式,但是不能直接(FFT),因为我们并不知道(f_{i-j}),于是考虑分治。
按照CDQ分治的方法,对于当前处理的区间([l,r]),我们先处理([l,mid]),之后考虑([l,mid])对([mid+1,r])的贡献,写出来就是:(f_i+=sumlimits_{j=l}^{mid}f_j*g_{i-j})。
模板题
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
const int mod=998244353;
const int G=3;
const int invG=332748118;
int n,lim,len;
int f[maxn],g[maxn],tmp1[maxn],tmp2[maxn],pos[maxn];
inline int read()
{
char c=getchar();int res=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
return res*f;
}
inline int power(int x,int k)
{
int res=1;
while(k)
{
if(k&1)res=1ll*res*x%mod;
x=1ll*x*x%mod;k>>=1;
}
return res;
}
inline void NTT(int* a,int op)
{
for(int i=0;i<lim;i++)if(i<pos[i])swap(a[i],a[pos[i]]);
for(int l=1;l<lim;l<<=1)
{
int wn=power(op==1?G:invG,(mod-1)/(l<<1));
for(int i=0;i<lim;i+=l<<1)
{
int w=1;
for(int j=0;j<l;j++,w=1ll*w*wn%mod)
{
int x=a[i+j],y=1ll*w*a[i+l+j]%mod;
a[i+j]=(x+y)%mod;a[i+l+j]=(x-y+mod)%mod;
}
}
}
if(op==1)return;
int inv=power(lim,mod-2);
for(int i=0;i<lim;i++)a[i]=1ll*a[i]*inv%mod;
}
void solve(int l,int r)
{
if(l==r)return;
int mid=(l+r)>>1;
solve(l,mid);
for(int i=l;i<=mid;i++)tmp1[i-l]=f[i],tmp2[i-l]=g[i-l];
for(int i=mid+1;i<=r;i++)tmp1[i-l]=0,tmp2[i-l]=g[i-l];
lim=1,len=0;
while(lim<=r-l)lim<<=1,len++;
for(int i=0;i<lim;i++)pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
for(int i=r-l+1;i<lim;i++)tmp1[i]=tmp2[i]=0;
NTT(tmp1,1);NTT(tmp2,1);
for(int i=0;i<lim;i++)tmp1[i]=1ll*tmp1[i]*tmp2[i]%mod;
NTT(tmp1,-1);
for(int i=mid+1;i<=r;i++)f[i]=(f[i]+tmp1[i-l])%mod;
solve(mid+1,r);
}
int main()
{
n=read();
for(int i=1;i<n;i++)g[i]=read();
f[0]=1;
int l=1;
while(l<=n)l<<=1;
solve(0,l);
for(int i=0;i<n;i++)printf("%d ",f[i]);
return 0;
}
以上是关于分治FFT的主要内容,如果未能解决你的问题,请参考以下文章