• 分治 FFT


    为啥要叫分治(fft)啊,又用不到(fft……)

    给定长度为(n-1)的数组(g[1],g[2],……,g[n-1]),求(f[1],f[2],……,f[n]),其中

    [f[i]=sumlimits_{j=1}^{i}f[j-i]g[j] ]

    边界为(f[0]=1),答案模(998244353)

    (2le n le 10^5,0le g[i]< 998244353)

    我们发现这其实是一个关于(f)数组的递推式子,但是肯定不能直接递推

    考虑每个对(f[i])有贡献的只有(f[1]sim f[i-1]),我们可以用(cdq)分治

    假设我们求出了(f[l->mid])的答案,想计算对(f[mid+1->r])的贡献

    那么对(tin [mid+1,r])的贡献为 (val_t=sumlimits_{i=l}^{mid}f[i]*g[t-i])

    是一个卷积形式,可以(ntt),得出(val_t)后直接加给(f[t])就好了

    其实点名是(cdq)分治思路就很清晰了吧,不过边界一如既往的恶心我

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=5e5+10,p=998244353,G=3,gi=332748118;
    	int n;
    	int g[N],f[N],pos[N];
    	int a[N],b[N];
    	inline int fast(int x,int k)
    	{
    		int ret=1;
    		while(k)
    		{
    			if(k&1) ret=ret*x%p;
    			x=x*x%p;
    			k>>=1;
    		}
    		return ret;
    	}
    	inline void ntt(int *a,int inv,int limit)
    	{
    		for(int i=0;i<limit;++i)
    			if(i<pos[i]) swap(a[i],a[pos[i]]);
    		for(int mid=1;mid<limit;mid<<=1)
    		{
    			int Wn=fast(inv?G:gi,(p-1)/(mid<<1));
    			for(int r=mid<<1,j=0;j<limit;j+=r)
    			{
    				int w=1;
    				for(int k=0;k<mid;++k,w=w*Wn%p)
    				{
    					int x=a[j+k],y=w*a[j+k+mid]%p;
    					a[j+k]=x+y;
    					if(a[j+k]>=p) a[j+k]-=p;
    					a[j+k+mid]=x-y;
    					if(a[j+k+mid]<0) a[j+k+mid]+=p;
    				}
    			}
    		}
    		if(inv) return;
    		inv=fast(limit,p-2);
    		for(int i=0;i<limit;++i) a[i]=a[i]*inv%p;
    	}
    	inline void cdq(int l,int r)
    	{
    		if(l==r) return;
    		int mid=(l+r)>>1;
    		cdq(l,mid);
    		int limit=1,len=0;
    		while(limit<=(mid-l+1)*2) limit<<=1,++len;
    		for(int i=0;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    		for(int i=0;i<limit;++i) a[i]=b[i]=0;
    		for(int i=l;i<=mid;++i) a[i-l]=f[i];
    		for(int i=1;i<=r-l+1;++i) b[i-1]=g[i];
    		ntt(a,1,limit);ntt(b,1,limit);
    		for(int i=0;i<limit;++i) a[i]=a[i]*b[i]%p;
    		ntt(a,0,limit);
    		for(int i=mid+1;i<=r;++i) (f[i]+=a[i-l-1])%=p;
    		cdq(mid+1,r);
    	}
    	inline void main()
    	{
    		n=read();
    		f[0]=1;
    		for(int i=1;i<n;++i) g[i]=read();
    		cdq(0,n-1);
    		for(int i=0;i<n;++i) printf("%lld ",f[i]);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    
  • 相关阅读:
    初识ES6
    初识NODE
    AJAX详解
    PHP 文件与目录操作函数总结
    PHP封装一个通用好用的文件上传处理类
    PHP基础之 错误处理 及 异常处理
    PHP基础OOP(二) 多态
    PHP基础之 重载 的实现方式
    CCS3的过渡、变换、动画以及响应式布局、弹性布局
    CSS之盒子模型(由浅到深的理解)
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12056106.html
Copyright © 2020-2023  润新知