版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/84325973
传送门:luogu【模板】分治 FFT
题意
给定长度为
的数组
,求
,其中
边界
。答案模
。
题解
法1(cdq分治):
模数当然用 咯。
考虑后面的只与前面有关,可以 cdq分治。
假设已经求出 ,则这些答案对 的贡献: ,卷积计算即可。
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+100,mod=998244353,gen=3;
typedef long long ll;
int n,f[N],g[N];
int a[N],b[N],ivg,len,rv[N];
inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}
inline int fp(int x,int y)
{
int re=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1) re=(ll)re*x%mod;
return re;
}
inline void ntt(int *c,int pr)
{
int i,j,k,ori,pd,ix,iy,G=pr?gen:ivg;
for(i=1;i<len;++i) if(i<rv[i]) swap(c[i],c[rv[i]]);
for(i=1;i<len;i<<=1){
ori=fp(G,(mod-1)/(i<<1));
for(j=0;j<len;j+=(i<<1)){
pd=1;
for(k=0;k<i;++k,pd=(ll)pd*ori%mod){
ix=c[j+k];iy=(ll)c[i+j+k]*pd%mod;
c[j+k]=ad(ix,iy);c[i+j+k]=dc(ix,iy);
}
}
}
if(pr) return;
G=fp(len,mod-2);
for(i=0;i<len;++i) c[i]=(ll)c[i]*G%mod;
}
void cdq(int l,int r)
{
if(l==r) return;
int i,L=0,mx=(r-l+1)<<1,mid=(l+r)>>1;
cdq(l,mid);
for(len=1;len<mx;len<<=1) L++;
for(i=1;i<len;++i) rv[i]=((rv[i>>1]>>1)|((i&1)<<(L-1)));
for(i=l;i<=mid;++i) a[i-l]=f[i];
for(i=mid+1-l;i<len;++i) a[i]=0;
for(i=0,mx=r-l;i<=mx;++i) b[i]=g[i];
for(i=mx+1;i<len;++i) b[i]=0;
ntt(a,1);ntt(b,1);
for(i=0;i<len;++i) a[i]=(ll)a[i]*b[i]%mod;
ntt(a,0);
for(i=mid+1;i<=r;++i)
f[i]=ad(f[i],a[i-l]);
cdq(mid+1,r);
}
int main(){
int i;scanf("%d",&n);f[0]=1;ivg=fp(gen,mod-2);
for(i=1;i<n;++i) scanf("%d",&g[i]);
cdq(0,n-1);
for(i=0;i<n;++i) printf("%d ",f[i]);
return 0;
}
法2(多项式求逆):
的生成函数长成这样:
由
转化一下得到:
套多项式求逆模板即可
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+100,mod=998244353,gen=3;
typedef long long ll;
int n,f[N],g[N];
int a[N],b[N],ivg,len,rv[N];
inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}
inline int fp(int x,int y)
{
int re=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1) re=(ll)re*x%mod;
return re;
}
inline void ntt(int *c,int pr)
{
int i,j,k,ori,pd,ix,iy,G=pr?gen:ivg;
for(i=1;i<len;++i) if(i<rv[i]) swap(c[i],c[rv[i]]);
for(i=1;i<len;i<<=1){
ori=fp(G,(mod-1)/(i<<1));
for(j=0;j<len;j+=(i<<1)){
pd=1;
for(k=0;k<i;++k,pd=(ll)pd*ori%mod){
ix=c[j+k];iy=(ll)c[i+j+k]*pd%mod;
c[j+k]=ad(ix,iy);c[i+j+k]=dc(ix,iy);
}
}
}
if(pr) return;
G=fp(len,mod-2);
for(i=0;i<len;++i) c[i]=(ll)c[i]*G%mod;
}
void gtnv(int n,int *f,int *g)
{
if(n==1) {g[0]=1;return;}
gtnv((n+1)>>1,f,g);
int i,j,L=0;
for(len=1;len<n+n;len<<=1) L++;
for(i=1;i<len;++i) rv[i]=((rv[i>>1]>>1)|((i&1)<<(L-1)));
for(i=0;i<n;++i) a[i]=f[i];
for(i=n;i<len;++i) a[i]=0;
ntt(a,1);ntt(g,1);
for(i=0;i<len;++i) g[i]=(ll)g[i]*dc(2,(ll)a[i]*g[i]%mod)%mod;
ntt(g,0);
for(i=n;i<len;++i) g[i]=0;
}
int main(){
int i;scanf("%d",&n);ivg=fp(gen,mod-2);
for(i=1;i<n;++i) {scanf("%d",&g[i]);if(g[i]) g[i]=mod-g[i];}
g[0]=1;gtnv(n,g,f);
for(i=0;i<n;++i) printf("%d ",f[i]);
return 0;
}