分治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;
}
原文地址:https://www.cnblogs.com/nofind/p/12129300.html