静态数组版本
#include<bits/stdc++.h>
using namespace std;
const int mo=998244353;
const int maxn=1<<20;
int add(int x,int y){
return (x+y>=mo)?x+y-mo:x+y;
}
int sub(int x,int y){
return (x-y<0)?x-y+mo:x-y;
}
int mul(int x,int y){
return 1ll*x*y%mo;
}
#define gc getchar
int rd(){
int f=1,r=0;
char ch=gc();
while(!isdigit(ch)){ if(ch=='-') f=-1;ch=gc();}
while(isdigit(ch)){ r=(r<<1)+(r<<3)+(ch^48);ch=gc();}
return f*r;
}
int ksm(int x,int y){
int rs=1;
while(y){
if(y&1) rs=1ll*rs*x%mo;
x=1ll*x*x%mo;
y>>=1;
}
return rs;
}
int rev[maxn];
void init_rev(int len){
for(int i=0;i<len;++i){
rev[i]=rev[i>>1]>>1;
if(i&1) rev[i]|=len>>1;
}
}
namespace Polynomial{
struct poly{
int a[maxn];
poly(){memset(a,0,sizeof(a));};
int& operator[](int x){
return a[x];
}
int operator[](int x)const{
return a[x];
}
void operator=(const poly &t){
memcpy(a,t.a,sizeof(a));
return;
}
void slice(int len,int k){
for(int i=len;i<k;++i) a[i]=0;
}
void NTT(int len,int rv){
for(int i=0;i<len;++i) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int h=2;h<=len;h<<=1){
int wn=ksm(3,(mo-1)/h);
for(int i=0;i<len;i+=h){
int w=1;
for(int k=i;k<i+h/2;++k){
int u=a[k],v=mul(w,a[k+h/2]);
a[k]=add(u,v);
a[k+h/2]=sub(u,v);
w=mul(w,wn);
}
}
}
if(rv==-1){
reverse(a+1,a+len);
int inv=ksm(len,mo-2);
for(int i=0;i<len;++i) a[i]=mul(a[i],inv);
}
}
poly inv(int len)const{
poly g,g0,d;
g[0]=ksm(a[0],mo-2);
for(int lim=2;(lim>>1)<len;lim<<=1){
g0=g,d=*this;
d.slice(lim,len);
int k=lim<<1;
init_rev(k);
g0.NTT(k,1),d.NTT(k,1);
for(int i=0;i<k;++i) g0[i]=mul(g0[i],sub(2,mul(g0[i],d[i])));
g0.NTT(k,-1);
g0.slice(lim,k);
g=g0;
}
return g;
}
poly der(int len)const{
poly g=*this;
for(int i=0;i<len;++i) g[i]=mul(g[i+1],i+1);
return g;
}
poly integ(int len)const{
poly g=*this;
for(int i=len-1;i;--i) g[i]=mul(g[i-1],ksm(i,mo-2));
g[0]=0;
return g;
}
poly ln(int len)const{
poly d=this->der(len),iv=this->inv(len),rs;
int k=len<<1;
init_rev(k);
d.NTT(k,1),iv.NTT(k,1);
for(int i=0;i<k;++i) rs[i]=mul(d[i],iv[i]);
rs.NTT(k,-1);
rs=rs.integ(k);
rs.slice(len,k);
return rs;
}
poly Exp(int len)const{
poly g,g0,lng,d;
g[0]=1;
int k;
for(int lim=2;(lim>>1)<len;lim<<=1){
k=lim<<1;
g0=g,lng=g.ln(k),d=*this;
d.slice(lim,k);
lng.slice(lim,k);
init_rev(k);
g0.NTT(k,1),lng.NTT(k,1),d.NTT(k,1);
for(int i=0;i<k;++i) g[i]=mul(g0[i],add(sub(1,lng[i]),d[i]));
g.NTT(k,-1);
g.slice(lim,k);
}
g.slice(len,k);
return g;
}
poly Mul(int len,int k)const{
poly rs=*this;
for(int i=0;i<len;++i) rs[i]=mul(rs[i],k);
return rs;
}
poly pow(int len,int k)const{
poly rs=this->ln(len);
rs=rs.Mul(len,k);
rs=rs.Exp(len);
return rs;
}
poly rv(int len)const{
poly rs=*this;
reverse(rs.a,rs.a+len);
return rs;
}
pair<poly,poly> modulo(int n,int m,const poly g)const{
poly rf=this->rv(n+1),rg=g.rv(m+1),q,r;
rf.slice(n-m+1,n+1),rg.slice(n-m+1,m+1);
int k=1;
while(k<=(n-m+1)) k<<=1;
rg=rg.inv(k);
while(k<=(n-m+1)*2) k<<=1;
init_rev(k);
rf.NTT(k,1),rg.NTT(k,1);
for(int i=0;i<k;++i) q[i]=mul(rf[i],rg[i]);
q.NTT(k,-1);
q.slice(n-m+1,k);
q=q.rv(n-m+1);
poly f=*this,G=g;
k=1;
while(k<=2*max(n+1,m+1)) k<<=1;
init_rev(k);
f.NTT(k,1),G.NTT(k,1),q.NTT(k,1);
for(int i=0;i<k;++i) r[i]=sub(f[i],mul(q[i],G[i]));
r.NTT(k,-1),q.NTT(k,-1);
q.slice(n-m+1,k);
r.slice(m,k);
return make_pair(q,r);
}
};
}
using namespace Polynomial;
vector 版本
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
constexpr int mo=998244353,maxn=1<<21;
int n;
inline int add(int x,int y){
x+=y;return x<mo?x:x-mo;
}
inline void upd(int &x,int y){
x=add(x,y);return;
}
int ksm(int x,int y){
int rs=1;for(;y;y>>=1,x=(i64)x*x%mo) if(y&1) rs=(i64)rs*x%mo;return rs;
}
int inv[maxn];
void initinv(){
inv[1]=1;for(int i=2;i<maxn;++i) inv[i]=(i64)(mo-mo/i)*inv[mo%i]%mo;
}
int rev[maxn];
inline int getmi(int n){
int len=1;while(len<n) len<<=1;
return len;
}
int initrev(int n){
int len=getmi(n);
for(int i=1;i<len;++i){
rev[i]=rev[i>>1]>>1;
if(i&1) rev[i]|=len>>1;
}
return len;
}
struct Poly{
vector<int> v;
int L;
Poly(){vector<int>().swap(v);L=0;}
int& operator[](int x){
return v[x];
}
void slice(int len){ v.resize(len);L=len;}
void NTT(int len,bool typ){
for(int i=1;i<len;++i) if(i<rev[i]) swap(v[i],v[rev[i]]);
for(int h=2;h<=len;h<<=1){
int w=ksm(3,(mo-1)/h);
for(int i=0;i<len;i+=h){
int wn=1;
for(int j=i;j<i+h/2;++j){
int x=v[j],y=(i64)wn*v[j+h/2]%mo;
v[j]=add(x,y);v[j+h/2]=add(x,mo-y);
wn=(i64)wn*w%mo;
}
}
}
if(!typ){
reverse(v.begin()+1,v.end());
for(int i=0;i<len;++i) v[i]=(i64)v[i]*inv[len]%mo;
}
}
Poly operator*(const Poly &F){
Poly rs,f,g;f=*this;g=F;
int len=initrev(L+F.L-1);
f.slice(len);g.slice(len);rs.slice(len);
f.NTT(len,1);g.NTT(len,1);
for(int i=0;i<len;++i) rs.v[i]=(i64)f.v[i]*g.v[i]%mo;
rs.NTT(len,0);
return rs;
}
Poly Inv(){
Poly g,g0,f;
int Lim=getmi(L);
g.slice(1);g[0]=ksm(v[0],mo-2);
for(int len=2;(len>>1)<Lim;len<<=1){
f=*this;f.slice(len);
len<<=1;
f.slice(len);g.slice(len);g0=g;
initrev(len);
g0.NTT(len,1);f.NTT(len,1);
for(int i=0;i<len;++i) g[i]=(i64)g0[i]*add(2,mo-(i64)f[i]*g0[i]%mo)%mo;
g.NTT(len,0);
len>>=1;
g.slice(len);
}
g.slice(L);
return g;
}
Poly Der(){
Poly rs;rs.slice(L-1);
for(int i=1;i<=L-1;++i) rs[i-1]=(i64)v[i]*i%mo;
return rs;
}
Poly Int(){
Poly rs;rs.slice(L+1);rs[0]=0;
for(int i=1;i<=L;++i) rs[i]=(i64)v[i-1]*inv[i]%mo;
return rs;
}
Poly Ln(){
Poly rs=(this->Der())*(this->Inv());
rs=rs.Int();rs.slice(L);
return rs;
}
Poly Exp(){
Poly f,g,g0,gln;
int Lim=getmi(L);
g.slice(1);g[0]=1;
for(int len=2;(len>>1)<Lim;len<<=1){
f=*this;f.slice(len);
g.slice(len);gln=g.Ln();gln.slice(len);
len<<=1;
f.slice(len);gln.slice(len);g.slice(len);g0=g;
initrev(len);
g0.NTT(len,1);f.NTT(len,1);gln.NTT(len,1);
for(int i=0;i<len;++i) g[i]=(i64)g0[i]*add(1,add(mo-gln[i],f[i]))%mo;
g.NTT(len,0);
len>>=1;
g.slice(len);
}
g.slice(L);
return g;
}
}F,ans;
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
initinv();
cin>>n;
F.slice(n);
for(int i=0;i<n;++i) cin>>F[i];
ans=F.Exp();
for(int i=0;i<n;++i) cout<<ans[i]<<' ';cout<<'\n';
return 0;
}