题目
题目背景
也可用多项式求逆解决。
题目描述
给定序列 g_{1\dots n - 1}g
1…n−1
,求序列 f_{0\dots n - 1}f
0…n−1
。
其中 f_i=\sum_{j=1}^if_{i-j}g_jf
i
=∑
j=1
i
f
i−j
g
j
,边界为 f_0=1f
0
=1。
答案对 998244353998244353 取模。
输入格式
第一行一个整数 nn 。
第二行 n-1n−1 个整数 g_{1\dots n - 1}g
1…n−1
。
输出格式
一行 nn 个整数,表示 f_{0\dots n - 1}f
0…n−1
对 998244353998244353 取模后的值。
输入输出样例
输入 #1 复制
4
3 1 2
输出 #1 复制
1 3 10 35
输入 #2 复制
10
2 456 32 13524543 998244352 0 1231 634544 51
输出 #2 复制
1 2 460 1864 13738095 55389979 617768468 234028967 673827961 708520894
说明/提示
2\leq n\leq 10^52≤n≤10
5
,0\leq g_i<9982443530≤g
i
<998244353。
思路
用cdq分治+NTT
每次处理[l,mid]对[mid+1,r]的贡献
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=4e5+77,mod=998244353,G=3;
int lg=0,len=1;
ll a[N],b[N],g[N],f[N];
int rev[N];
ll power(ll x,ll t)
{
ll b=1;
while(t)
{
if(t&1) b=b*x%mod;
x=x*x%mod; t>>=1;
}
return b;
}
void dft(ll *a,int n,int aii)
{
for(int i=0; i<n; i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int i=2; i<=n; i<<=1)
{
int now=i>>1;
ll wn=power(G,(mod-1)/i);
if(aii==-1) wn=power(wn,mod-2);
for(int j=0; j<n; j+=i)
{
ll w=1,x,y;
for(int k=j; k<j+now; k++,w=w*wn%mod)
{
x=a[k],y=w*a[k+now]%mod;
a[k]=(x+y)%mod; a[k+now]=(x-y+mod)%mod;
}
}
}
if(aii==-1) for(int i=0; i<=n; i++) a[i]=a[i]*power(n,mod-2)%mod;
}
void NTT(ll *a,ll *b,int n,int m)
{
dft(a,len,1); dft(b,len,1);
for(int i=0; i<=len; i++) a[i]=a[i]*b[i]%mod;
dft(a,len,-1);
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid);
int n=r-l+1; len=1; lg=0;
while(len<=n)
{
len<<=1; lg++;
}
for(int i=0; i<len; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),a[i]=b[i]=0;
for(int i=l; i<=mid; i++) a[i-l]=f[i];
for(int i=1; i<=r-l; i++) b[i-1]=g[i];
NTT(a,b,mid-l+1,r-l);
for(int i=mid+1; i<=r; i++) f[i]=(f[i]+a[i-l-1])%mod;
cdq(mid+1,r);
}
int n;
int main()
{
scanf("%d",&n);
for(int i=1; i<n; i++) scanf("%lld",&g[i]);
f[0]=1;
cdq(0,n-1);
for(int i=0; i<n; i++) printf("%lld ",f[i]);
}