우리는 파티션을 부를 것이다 왜 \ FFT (\) 아, 이하 \ (FFT ...... \)
주어진 길이 \ (N-1 \) 배열 \ (G [. 1], G [2], ..., G [. 1-N-] \) 추구 \ (F [1], F [2] ..., F [N-] \) ,
\ [F [I] = \
합계 \ limits_ J = {1} ^ {I} F [지] g [J] \] 경계 \ (F [0] = 1 \) , 응답 모드 (\ 998 244 353 \)
\ (2 \ K \ 10 ^ 5,0 \ g [IN] <998,244,353 \)
우리는이에 대해 실제로 것을 발견 (F \) \ 순환 식 배열, 그러나 확실하게 직접 재귀하지
각 고려 (F [I]를 \) \ 에만 기여 (F [1] \ 심 (F)는 [I-1] \) \ , 우리가 사용 (CDQ \) \ 나누기 컨커
우리가 가정 발견 (F [1-> 미드] \ \) 의 계산과 마찬가지로 대답 \ (F [중간 + 1> R] \) 기여
이어서 \ ([중간 +에서 t \ 1, R은] \) 받는 기여 \ (val_t = \ 합계 \ limits_ ^ {중간} F [I] * g [TI] \ {나 패 =})
길쌈 캔이다 \ (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;
}