把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P4721 【模板】分治 FFT

题面传送门
为什么写的是分治NTT啊,有哪位大佬会实数取模的FFT教我一下。
首先观察这个东西不是很好搞。因为后面要基于前面的转移。
但是我们发现如果用分治就可以无视这个限制。
所以用cdq分治,转移区间为\([l,r]\)中点\(mid\)就先把\(f\)\([l,mid]\)\(g\)\([0,r-l]\)卷起来,然后转移到后面即可。
时间复杂度\(O(nlog^2n)\),常数还是蛮小的。
先把序列长度补成\(2\)的幂次会好写一点。
code:

#include<cstdio>
#define G 3
#define mod 998244353
#define ll long long
inline ll mpow(ll x,int y=mod-2){
	ll ans=1;
	while(y){if(y&1) ans=ans*x%mod;x=x*x%mod;y>>=1;}
	return ans;
}
const ll invG=mpow(G);
using namespace std;
int n,m,k,x,y,z,tr[400039];
ll g[400039],f[400039],ans[400039],a[400039];
inline void make(int x){for(int i=0;i<x;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?x>>1:0);}
inline void swap(ll &x,ll &y){x^=y^=x^=y;}
inline void ntt(ll *f,int n,int flag){
	register int i,j,k;ll pus,key,now;
	for(i=0;i<n;i++) if(tr[i]>i) swap(f[tr[i]],f[i]);
	for(i=2;i<=n;i<<=1){
		for(key=mpow(flag?G:invG,(mod-1)/i),j=0;j<n;j+=i){
			for(pus=1,k=j;k<j+i/2;k++)now=f[k+i/2]*pus%mod,f[k+i/2]=(f[k]-now+mod)%mod,f[k]=(f[k]+now)%mod,pus=pus*key%mod;
		}
	}
}
inline void solve(int l,int r){
	if(l==r){ans[l]=(ans[l]+a[l])%mod;return;}
	int mid=l+r>>1,i,m=(r-l+1)*2;solve(l,mid);
	for(i=0;i<m;i++) f[i]=g[i]=0;
	for(i=l;i<=mid;i++)f[i-l]=ans[i];
	for(i=0;i<r-l+1;i++)g[i]=a[i];make(m);
	ntt(f,m,1);ntt(g,m,1);
	for(i=0;i<m;i++) f[i]=f[i]*g[i]%mod;ntt(f,m,0);ll invn=mpow(m);
	for(i=0;i<m;i++) f[i]=f[i]*invn%mod;
	for(i=mid-l+1;i<r-l+1;i++) ans[l+i]=(ans[l+i]+f[i])%mod;solve(mid+1,r);
}
int main(){
	freopen("1.in","r",stdin);
	register int i;
	scanf("%d",&n);
	for(m=1;m<n;m<<=1);ans[0]=1;
	for(i=1;i<n;i++)scanf("%lld",&a[i]);
	solve(1,m);
	for(i=0;i<n;i++)printf("%lld ",ans[i]);
}
posted @ 2021-02-20 16:36  275307894a  阅读(46)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end