文件详细信息
本文件的大小为 8459 字节。
#include<chrono>
#include<cstdio>
#include<random>
#include<functional>
#include<vector>
namespace IO{
const int ARR_SIZE=1<<20;
#define gc() ((IO::si!=IO::ti||(IO::ti=(IO::si=IO::input)+fread(IO::input,1,IO::ARR_SIZE,stdin))),IO::si!=IO::ti?*(IO::si++):EOF)
#define pc(ch) ((IO::o.so!=IO::o.to||(fwrite(IO::o.output,1,IO::ARR_SIZE,stdout),IO::o.so=IO::o.output)),*(IO::o.so++)=ch)
char input[ARR_SIZE],*si=input,*ti=input;
struct Output_Stream{
char output[ARR_SIZE],*so=output,*to=output+ARR_SIZE;
~Output_Stream(){
if(so==output)return;
fwrite(output,1,so-output,stdout);
so=output;
}
}o;
template<typename T>
void read(T&num){
int ch=gc();
num=0;
while(ch<48||ch>57)ch=gc();
while(ch>=48&&ch<=57)num=(num<<3)+(num<<1)+(ch^48),ch=gc();
}
template<typename T>
void write(T a){
static int ch[50],cnt=0;
if(a<0)pc('-'),a=-a;
if(a==0)pc('0');
while(a)ch[++cnt]=a%10|48,a/=10;
while(cnt)pc(ch[cnt--]);
}
void putstr(const char*str){
while(*str!='\0')pc(*(str++));
}
}
using IO::read;
using IO::write;
using IO::putstr;
std::mt19937_64 rnd(std::chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=1<<18;
const ll P=998244353;
inline void qmod(int&x){
x=x+((x>>31)&int(P));
}
inline void qmod(ll&x){
x=x+((x>>63)&P);
}
template<typename T>
void swap(T&a,T&b){
const T temp=a;
a=b;
b=temp;
}
ll qpow(ll a,int x=P-2){
ll answer=1;
while(x){
if(x&1)answer=answer*a%P;
a=a*a%P;
x>>=1;
}
return answer;
}
inline int get_n(const int deg){
int n=1;
while(n<=deg)n<<=1;
return n;
}
const ll PR=3,invPR=qpow(PR),inv_2=qpow(2);
namespace QuadraticResidue{
ll n,p,a,w;
struct CP{
ll x,y;
};
CP operator*(CP x,CP y){
return CP{(x.x*y.x+x.y*y.y%p*w)%p,(x.x*y.y+x.y*y.x)%p};
}
ll qpow(ll a,ll x){
ll ans=1;
while(x){
if(x&1)ans=ans*a%p;
a=a*a%p;
x>>=1;
}
return ans;
}
ll qpow(CP a,ll x){
CP ans=CP{1,0};
while(x){
if(x&1)ans=ans*a;
a=a*a;
x>>=1;
}
return ans.x;
}
ll solve(){
n%=p;
if(n==0)return 0;
if(p==2)return n;
if(qpow(n,p>>1)==p-1)return-1;
do a=rnd()%p,w=(p+a*a-n)%p;
while(qpow(w,p>>1)!=p-1);
const ll ans=qpow(CP{a,1},(p+1)>>1);
if((ans<<1)>p)return p-ans;
return ans;
}
}
struct Inverse{
int inv[maxn+1];
Inverse(){
inv[1]=1;
for(int i=2;i<=maxn;i++)inv[i]=ll(P-P/i)*inv[P%i]%P;
}
int operator[](const int x){
return inv[x];
}
}inv;
template<const int size>
struct Transform{
private:
int tr[size],size_now;
public:
void init(const int n){
if(size_now==n)return;
size_now=n;
for(int i=0;i<n;i++)tr[i]=(tr[i>>1]>>1)|((i&1)?(n>>1):0);
}
int operator[](const int x)const{
return tr[x];
}
};
Transform<maxn<<1>tr;
template<typename T_store,typename T_calc>
struct Poly{
private:
std::vector<T_store>v;
public:
int operator[](const T_store x)const{
return v[x];
}
int deg(){
return(int)v.size()-1;
}
void set_deg(const int n){
v.resize(n+1);
}
void init(const int n){
v.resize(n+1);
for(int i=0;i<=n;i++)read(v[i]);
}
void output(){
const int d=deg();
for(int i=0;i<=d;i++)write(v[i]),pc(i!=d?' ':'\n');
}
void ntt(const bool type,const int n){
tr.init(n);
v.resize(n);
for(int i=0;i<n;i++)
if(i<tr[i])
swap(v[i],v[tr[i]]);
for(int p=2;p<=n;p<<=1){
const int len=p>>1;
const T_calc tPR=qpow(type?PR:invPR,(P-1)/p);
for(int k=0;k<n;k+=p){
T_calc buf=1;
for(int l=k;l<k+len;l++){
const T_calc temp=buf*v[l+len]%P;
qmod(v[l+len]=v[l]-temp);
qmod(v[l]+=temp-P);
buf=buf*tPR%P;
}
}
}
}
friend Poly<T_store,T_calc>operator*(Poly<T_store,T_calc>&F,const T_calc G){
Poly H;
H.v.resize(F.v.size());
for(int i=0;i<(int)F.v.size();i++)H.v[i]=F.v[i]*G%P;
return H;
}
friend Poly<T_store,T_calc>operator-(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G){
Poly<T_store,T_calc>H;
int len1=F.deg(),len2=G.deg();
if(len1<len2){
H.set_deg(len2);
for(int i=0;i<=len1;i++)qmod(H.v[i]=F[i]-G[i]);
for(int i=len1+1;i<=len2;i++)qmod(H.v[i]=-G[i]);
}else{
H.set_deg(len1);
for(int i=0;i<=len2;i++)qmod(H.v[i]=F[i]-G[i]);
for(int i=len2+1;i<=len1;i++)H.v[i]=F[i];
}
return H;
}
friend Poly<T_store,T_calc>operator*(Poly<T_store,T_calc>F,Poly<T_store,T_calc>G){
const int len=F.deg()+G.deg(),n=get_n(len);
F.ntt(true,n);
G.ntt(true,n);
Poly<T_store,T_calc>H;
H.v.resize(n);
for(int i=0;i<n;i++)H.v[i]=(T_calc)F.v[i]*G.v[i]%P;
H.ntt(false,n);
H.set_deg(len);
return H*qpow(n);
}
friend Poly<T_store,T_calc>poly_multiply(Poly<T_store,T_calc>F,Poly<T_store,T_calc>G,std::function<T_store(T_store,T_store)>func){
const int len=F.deg()+G.deg(),n=get_n(len);
F.ntt(true,n);
G.ntt(true,n);
Poly<T_store,T_calc>H;
H.v.resize(n);
for(int i=0;i<n;i++)H.v[i]=func(F.v[i],G.v[i]);
H.ntt(false,n);
H.set_deg(len);
return H*qpow(n);
}
friend Poly<T_store,T_calc>poly_multiply_reference(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G,std::function<T_store(T_store,T_store)>func){
const int len=F.deg()+G.deg(),n=get_n(len);
F.ntt(true,n);
G.ntt(true,n);
Poly<T_store,T_calc>H;
H.v.resize(n);
for(int i=0;i<n;i++)H.v[i]=func(F.v[i],G.v[i]);
H.ntt(false,n);
H.set_deg(len);
return H*qpow(n);
}
friend void poly_inverse(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G){
const int len=F.deg(),n=get_n(len);
F.v.resize(n<<1);
G.v.clear();
G.v.reserve(n<<1);
G.v.emplace_back(qpow(F[0]));
Poly<T_store,T_calc>A,B;
A.v.reserve(n<<1);
B.v.reserve(n<<1);
for(int l=1;l<=(len<<1);l<<=1){
const int lim=l<<1;
A.v.clear();
A.v.insert(A.v.begin(),F.v.begin(),F.v.begin()+l);
B.v.clear();
B.v.insert(B.v.begin(),G.v.begin(),G.v.begin()+l);
G=poly_multiply_reference(A,B,[](const T_store x,const T_store y){
return T_store((P+2-(T_calc)x*y%P)*y%P);
});
for(int i=l;i<lim;i++)G.v[i]=0;
}
F.set_deg(len);
G.set_deg(len);
}
friend void poly_sqrt(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G){
const int len=F.deg(),n=get_n(len);
F.v.resize(n<<1);
G.v.clear();
G.v.resize(n<<1);
QuadraticResidue::n=F[0],QuadraticResidue::p=P;
G.v[0]=QuadraticResidue::solve();
Poly<T_store,T_calc>A,B,invB;
A.v.reserve(n<<1);
B.v.reserve(n<<1);
invB.v.reserve(n<<1);
for(int l=1;l<=(len<<1);l<<=1){
const int lim=l<<1;
A.v.clear();
A.v.insert(A.v.begin(),F.v.begin(),F.v.begin()+l);
B.v.clear();
B.v.insert(B.v.begin(),G.v.begin(),G.v.begin()+l);
poly_inverse(B,invB);
A=poly_multiply_reference(A,invB,[](const T_store x,const T_store y){
return T_store((T_calc)x*y%P);
});
for(int i=0;i<l;i++)G.v[i]=T_calc(A[i]+B[i])*inv_2%P;
for(int i=l;i<lim;i++)G.v[i]=0;
}
F.set_deg(len);
G.set_deg(len);
}
friend void poly_derivation(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G){
const int n=F.deg();
G.set_deg(n);
for(int i=1;i<=n;i++)G.v[i-1]=(T_calc)F[i]*i%P;
G.v[n]=0;
}
friend void poly_integral(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G){
const int n=F.deg();
G.set_deg(n);
for(int i=1;i<=n;i++)G.v[i]=(T_calc)F[i-1]*inv[i]%P;
G.v[0]=0;
}
friend void poly_ln(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G){
Poly<T_store,T_calc>F_derivation,F_inv,G_derivation;
poly_derivation(F,F_derivation);
poly_inverse(F,F_inv);
G_derivation=poly_multiply(F_derivation,F_inv,[](const T_store x,const T_store y){
return T_store((T_calc)x*y%P);
});
G_derivation.set_deg(F.deg());
poly_integral(G_derivation,G);
}
friend void poly_exp(Poly<T_store,T_calc>&F,Poly<T_store,T_calc>&G){
const int len=F.deg(),n=get_n(len);
F.v.resize(n<<1);
G.v.clear();
G.v.reserve(n<<1);
G.v.emplace_back(1);
Poly<T_store,T_calc>A,B,C;
A.v.reserve(n<<1);
B.v.reserve(n<<1);
for(int l=1;l<=(len<<1);l<<=1){
const int lim=l<<1;
A.v.clear();
A.v.insert(A.v.begin(),F.v.begin(),F.v.begin()+l);
B.v.clear();
B.v.insert(B.v.begin(),G.v.begin(),G.v.begin()+l);
poly_ln(B,C);
C=A-C;
qmod(C.v[0]+=1-P);
G=poly_multiply_reference(B,C,[](const T_store x,const T_store y){
return T_store((T_calc)x*y%P);
});
for(int i=l;i<lim;i++)G.v[i]=0;
}
F.set_deg(len);
G.set_deg(len);
}
};
Poly<int,ll>F,G;
int n;
int main(){
read(n),n--;
F.init(n);
poly_exp(F,G);
G.output();
return 0;
}