#include using namespace std; using ll=long long; using ull=unsigned long long; using P=pair; templateusing minque=priority_queue,greater>; templatebool chmax(T &a,const T &b){return (abool chmin(T &a,const T &b){return (a>b?(a=b,true):false);} templateistream &operator>>(istream &is,pair&p){is>>p.first>>p.second;return is;} templateistream &operator>>(istream &is,tuple&a){is>>std::get<0>(a)>>std::get<1>(a)>>std::get<2>(a);return is;} templateistream &operator>>(istream &is,array&a){for(auto&i:a)is>>i;return is;} templateistream &operator>>(istream &is,vector &a){for(auto &i:a)is>>i;return is;} templatevoid operator++(pair&a,int n){a.first++,a.second++;} templatevoid operator--(pair&a,int n){a.first--,a.second--;} templatevoid operator++(vector&a,int n){for(auto &i:a)i++;} templatevoid operator--(vector&a,int n){for(auto &i:a)i--;} #define overload3(_1,_2,_3,name,...) name #define rep1(i,n) for(int i=0;i<(int)(n);i++) #define rep2(i,l,r) for(int i=(int)(l);i<(int)(r);i++) #define rep(...) overload3(__VA_ARGS__,rep2,rep1)(__VA_ARGS__) #define reps(i,l,r) rep2(i,l,r) #define all(x) x.begin(),x.end() #define pcnt(x) __builtin_popcountll(x) #define fin(x) return cout<<(x)<<'\n',static_cast(0) #define yn(x) cout<<((x)?"Yes\n":"No\n") #define uniq(x) sort(all(x)),x.erase(unique(all(x)),x.end()) template inline int fkey(vector&z,T key){return lower_bound(z.begin(),z.end(),key)-z.begin();} ll myceil(ll a,ll b){return (a+b-1)/b;} template auto vec(const int (&d)[n],const T &init=T()){ if constexpr (id(d,init)); else return init; } #ifdef LOCAL #include #define SWITCH(a,b) (a) #else #define debug(...) static_cast(0) #define debugg(...) static_cast(0) #define SWITCH(a,b) (b) templateostream &operator<<(ostream &os,const pair&p){os<>testcase; for(int i=0;i vector>matrix_mul(const vector>&a,const vector>&b){ assert(a[0].size()==b.size()); vector>ret(a.size(),vector(b[0].size(),0)); rep(i,a.size())rep(j,b.size())rep(k,b[0].size())ret[i][k]+=a[i][j]*b[j][k]; return ret; } template vector>matrix_pow(vector>a,ll k){ assert(a.size()==a[0].size()); vector>ret(a.size(),vector(a.size(),0)); rep(i,a.size())ret[i][i]=1; while(k){ if(k&1)ret=matrix_mul(ret,a); a=matrix_mul(a,a); k>>=1; } return ret; } template T matrix_det(vector>a){ if(a.empty())return 1; assert(a.size()==a[0].size()); int n=a.size(); T ret=1; rep(i,n){ int id=-1; reps(j,i,n){ if(a[j][i]!=0){ id=j; break; } } if(id==-1)return 0; if(i!=id){ ret*=-1; swap(a[i],a[id]); } ret*=a[i][i]; T inv=a[i][i].inv(); rep(j,n)a[i][j]*=inv; reps(j,i+1,n){ T x=a[j][i]; rep(k,n)a[j][k]-=a[i][k]*x; } } return ret; } template vector>matrix_inv(vector>a){ assert(a.size()==a[0].size()); int n=a.size(); vector>ret(n,vector(n,0)); rep(i,n)ret[i][i]=1; rep(i,n){ int id=-1; reps(j,i,n){ if(a[j][i]!=0){ id=j; break; } } if(id==-1)return vector>(n,vector(n,0)); if(i!=id){ swap(a[i],a[id]); swap(ret[i],ret[id]); } T inv=a[i][i].inv(); rep(j,n){ a[i][j]*=inv; ret[i][j]*=inv; } rep(j,n)if(i!=j){ T x=a[j][i]; rep(k,n){ a[j][k]-=a[i][k]*x; ret[j][k]-=ret[i][k]*x; } } } return ret; } template std::pair,std::vector>>matrix_linear_equation(std::vector>mat,std::vectorc){ int n=mat.size(),m=mat[0].size(); assert(n==c.size()); int y=0; std::vector>detv; std::vectorrankv; for(int d=0;d=d;j--)mat[i][j]-=mat[i][d]*mat[y][j]; } detv.push_back({d,y++}); } for(int i=y;i{},std::vector>{}); std::vectorret1(m); std::vector>ret2(rankv.size(),std::vector(m)); for(auto [x,i]:detv)ret1[x]=c[i]; for(int d=0;d std::vectorinverse_table(long long l,long long r){ assert(l<=r); if(l==r)return std::vector{}; l=(l-1)%T::mod(); r=(r-1)%T::mod(); if(l<0)l+=T::mod(); if(r<0)r+=T::mod(); if(l>r){ int n=std::max(r,T::mod()-l); std::vectorfact(n+1),factinv(n+1); fact[0]=1; for(int i=1;i<=n;i++)fact[i]=fact[i-1]*T::raw(i); factinv[n]=fact[n].inv(); for(int i=n-1;i>=0;i--)factinv[i]=factinv[i+1]*T::raw(i+1); std::vectorret; ret.reserve(r-l+T::mod()); for(int i=l+1;iret(n); ret[0]=1; for(int i=1;i=0;i--){ ret[i]*=inv; inv*=T::raw(i+1+l); } return ret; } } #include #include struct is_modint_impl{ template static auto check(T&&x)->decltype(x.mod(),std::true_type{}); template static auto check(...)->std::false_type; }; template struct is_modint:public decltype(is_modint_impl::check(std::declval())){}; template inline constexpr bool is_modint_v=is_modint::value; struct is_dynamic_modint_impl{ template static auto check(T&&x)->decltype(x.set_mod((typename T::value_type)0),std::true_type{}); template static auto check(...)->std::false_type; }; template struct is_dynamic_modint:public decltype(is_dynamic_modint_impl::check(std::declval())){}; template inline constexpr bool is_dynamic_modint_v=is_dynamic_modint::value; template inline constexpr bool is_static_modint_v=is_modint_v&&!is_dynamic_modint_v; struct is_uso_modint_impl{ template static auto check(T&&x)->decltype(x.uso(),std::true_type{}); template static auto check(...)->std::false_type; }; template struct is_uso_modint:public decltype(is_uso_modint_impl::check(std::declval())){}; template inline constexpr bool is_uso_modint_v=is_uso_modint::value; template struct F{ private: static int capacity; static std::vectorfact,factinv,inv; public: static void resize(int n){ if(capacity>=n)return; fact.resize(n+1),factinv.resize(n+1),inv.resize(n+1); for(int i=capacity+1;i<=n;i++){ fact[i]=fact[i-1]*T::raw(i); if constexpr(is_uso_modint_v)inv[i]=T(1)/T(i); else inv[i]=-inv[T::mod()%i]*(T::mod()/i); factinv[i]=factinv[i-1]*inv[i]; } capacity=n; } static T C(int n,int k){ if(n static T O(INT...k){ int n=0; for(int i:std::initializer_list{k...}){ if(i<0)return 0; n+=i; } resize(n); T ret=fact[n]; for(int i:std::initializer_list{k...})ret*=factinv[i]; return ret; } }; templateint F::capacity=1; templatestd::vectorF::fact{1,1}; templatestd::vectorF::factinv{1,1}; templatestd::vectorF::inv{0,1}; #include template constexpr std::enable_if_t::digits<=32,int>msb(T n){return n==0?-1:31-__builtin_clz(n);} template constexpr std::enable_if_t<(std::numeric_limits::digits>32),int>msb(T n){return n==0?-1:63-__builtin_clzll(n);} template constexpr std::enable_if_t::digits<=32,int>lsb(T n){return n==0?-1:__builtin_ctz(n);} template constexpr std::enable_if_t<(std::numeric_limits::digits>32),int>lsb(T n){return n==0?-1:__builtin_ctzll(n);} template constexpr std::enable_if_t,T>floor_pow2(T n){return n==0?0:T(1)< constexpr std::enable_if_t,T>ceil_pow2(T n){return n<=1?1:T(1)<<(msb(n-1)+1);} template constexpr T safe_div(T a,T b){return a/b-(a%b&&(a^b)<0);} template constexpr T safe_ceil(T a,T b){return a/b+(a%b&&(a^b)>0);} template constexpr std::enable_if_t<(std::numeric_limits::digits<=32),T>pow_mod(T a,T n,T mod){ using u64=unsigned long long; u64 res=1; while(n>0){ if(n&1)res=((u64)res*a)%mod; a=((u64)a*a)%mod; n>>=1; } return T(res); } template constexpr std::enable_if_t<(std::numeric_limits::digits>32),T>pow_mod(T a,T n,T mod){ using u128=__uint128_t; u128 res=1; while(n>0){ if(n&1)res=((u128)res*a)%mod; a=((u128)a*a)%mod; n>>=1; } return T(res); } constexpr int primitive_root_constexpr(int x){ if(x==167772161)return 3; if(x==469762049)return 3; if(x==754974721)return 11; if(x==880803841)return 26; if(x==998244353)return 3; if(x==2)return 1; int x2=x; int p[20]={}; int c=0; x--; for(int i=2;i*i<=x;i++){ if(x%i==0){ p[c++]=i; while(x%i==0)x/=i; } } if(x!=1)p[c++]=x; x=x2; for(int g=2;;g++){ bool ok=true; for(int i=0;i struct ntt_root{ static constexpr int rank2=lsb(m-1); static constexpr int g=primitive_root_constexpr(m); std::arrayroot,invroot; std::arrayrate2,invrate2; std::arrayrate3,invrate3; constexpr ntt_root(){ root[rank2]=pow_mod(g,m>>rank2,m); invroot[rank2]=pow_mod(root[rank2],m-2,m); for(int i=rank2-1;i>=0;i--){ root[i]=(long long)root[i+1]*root[i+1]%m; invroot[i]=(long long)invroot[i+1]*invroot[i+1]%m; } int prod=1,invprod=1; for(int i=0;i void dft(std::vector&a){ static constexpr ntt_rootr; static constexpr unsigned long long mod2=(unsigned long long)T::mod()*T::mod(); int n=a.size(); int h=lsb(n); int len=0; while(len void idft(std::vector&a){ static constexpr ntt_rootr; int n=a.size(); int h=lsb(n); int len=h; while(len){ if(len==1){ int p=1<<(h-1); for(int i=0;i std::vectorntt_convolution(std::vector a,std::vector b){ int n=a.size(),m=b.size(),s=n+m-1; if(std::min(n,m)<60){ std::vectorret(s,0); if(nc(z); for(int i=0;i struct SWAG{ private: using S=typename M::S; std::vectora,b; std::vectorproda,prodb; void eval(){ proda.resize(a.size()+1,M::e()); prodb.resize(b.size()+1,M::e()); for(int i=1;i<(int)proda.size();i++)proda[i]=M::op(a[i-1],proda[i-1]); for(int i=1;i<(int)prodb.size();i++)prodb[i]=M::op(prodb[i-1],b[i-1]); } public: SWAG():proda{M::e()},prodb{M::e()}{} void push_front(S v){ a.emplace_back(move(v)); proda.emplace_back(M::op(a.back(),proda.back())); } void push_back(S v){ b.emplace_back(std::move(v)); prodb.emplace_back(M::op(prodb.back(),b.back())); } inline S front()const{return a.empty()?b[0]:a.back();} inline S back()const{return b.empty()?a[0]:b.back();} void pop_front(){ if(a.empty()){ int mid=b.size()/2; a=std::vector(b.rbegin()+mid,b.rend()); b=std::vector(b.end()-mid,b.end()); eval(); } a.pop_back(); proda.pop_back(); } void pop_back(){ if(b.empty()){ int mid=a.size()/2; b=vector(a.rbegin()+mid,a.rend()); a=vector(a.end()-mid,a.end()); eval(); } b.pop_back(); prodb.pop_back(); } inline S all_prod()const{return M::op(proda.back(),prodb.back());} inline int size()const{return a.size()+b.size();} inline bool empty()const{return a.empty()&&b.empty();} }; template std::vectorshift_sample_point(const std::vector&f,T k,int m=-1){ int n=f.size(); if(m==-1)m=n; int c=k.val(); std::vectora=inverse_table(c-n+1,c+m); std::vectorb(n); for(int i=0;i::factorial_inv(i)*F::factorial_inv(n-i-1)*f[i]; if((n-i-1)&1)b[i]=-b[i]; } int s=ceil_pow2(n+m-1); a.resize(s); b.resize(s); dft(a),dft(b); for(int i=0;i(a.begin()+n-1,a.begin()+n+m-1); T inv=T::raw(s).inv(); struct M{ using S=T; static inline S op(const S&x,const S&y){return x*y;} static inline S e(){return T::raw(1);} }; SWAGswag; for(int i=c-n+1;i<=c;i++)swag.push_back(i); for(int i=0;i vector>poly_matrix_prod(const vector>>&mat,ll k){ int n=mat.size(); auto shift=[](const vector>>&m,T x){ int d=m.size(),n=m[0].size(); vector>>ret(d,vector>(n,vector(n))); rep(i,n)rep(j,n){ vectorg(d); rep(l,d)g[l]=m[l][i][j]; g=shift_sample_point(g,x); rep(l,d)ret[l][i][j]=g[l]; } return ret; }; auto fx=[](const vector&f,T x)->T { T ret=0,power=1; rep(i,f.size()){ ret+=f[i]*power; power*=x; } return ret; }; int deg=1; rep(i,n)rep(j,n)chmax(deg,mat[i][j].size()-1); ll v=1; while(deg*v*v>>G(deg+1,vector>(n,vector(n))); T inv=T(v).inv(); rep(i,deg+1){ T x=T(v)*i; rep(j,n)rep(l,n)G[i][j][l]=fx(mat[j][l],x); } for(ll w=1;w>ret(n,vector(n,0)); rep(i,n)ret[i][i]=1; ll i=0; while(i+v<=k)ret=matrix_mul(G[i/v],ret),i+=v; while(i>mat2(n,vector(n)); rep(j,n)rep(l,n)mat2[j][l]=fx(mat[j][l],i); ret=matrix_mul(mat2,ret); i++; } return ret; } template vector>find_p_recursive(vectora,int d){ int n=a.size(); int k=(n+2)/(d+2)-1; if(k<=0)return {}; int m=(k+1)*(d+1); vector>mat(m-1,vector(m)); rep(i,m-1){ rep(j,k+1){ T p=1; rep(l,d+1){ mat[i][(d+1)*j+l]=p*a[i+j]; p*=i+j; } } } auto g=matrix_linear_equation(mat,vector(m-1,0)).second; if(g.empty())return vector>{}; vectorc=g[0]; while(all_of(c.end()-d-1,c.end(),[](T x){return x==0;}))c.erase(c.end()-d-1,c.end()); k=c.size()/(d+1); vector>ret(k); rep(j,k){ int i=j*(d+1); vectorf(1+d,0),sum(1+d,0); f[0]=1; rep(l,d+1){ rep(x,1+d)sum[x]+=f[x]*c[i+l]; for(int x=d;x>=1;x--)f[x]=f[x-1]+f[x]*j; f[0]*=j; } ret[j]=sum; } return ret; } template T calc_p_recursive_naive(const vector&a,const vector>&coef,ll n){ if(a.size()>n)return a[n]; int r=coef.size()-1; int d=coef[0].size()-1; assert(a.size()>=r); vector>que(r); rep(i,r)que[i]={a[i],1}; int ptr=0; for(ll i=0;i<=n-r;i++){ T num=0,den=1; rep(j,r){ T c=0,power=1; rep(k,d+1){ c+=coef[j][k]*power; power*=i; } int idx=ptr+j; if(idx>=r)idx-=r; num=num*que[idx].second+que[idx].first*den*c; den=den*que[idx].second; } T c=0,power=1; rep(k,d+1){ c+=coef[r][k]*power; power*=i; } que[ptr++]=make_pair(num,-den*c); if(ptr==r)ptr=0; } if(--ptr==-1)ptr=r-1; return que[ptr].first/que[ptr].second; } template T calc_p_recursive_fast(const vector&a,const vector>&coef,ll n){ if(a.size()>n)return a[n]; int deg=coef.size()-1; vector>>num(deg,vector>(deg)); rep(i,deg){ num[0][i]=coef[deg-i-1]; rep(j,num[0][i].size())num[0][i][j]=-num[0][i][j]; } reps(i,1,deg)num[i][i-1]=coef[deg]; vector>>den={{coef[deg]}}; vector>a0(deg,vector(deg,0)); rep(i,deg)a0[i][0]=a[deg-i-1]; T ret=matrix_mul(poly_matrix_prod(num,n-deg+1),a0)[0][0]; ret/=poly_matrix_prod(den,n-deg+1)[0][0]; return ret; } template T kth_term_p_recursive(vectora,int K){ if(K=5); int n=a.size()-2; for(int d=0;;d++){ int k=(n+2)/(d+2)-1; if(k<=0)break; int s=(n+2)/(d+2)*(d+2)-2; vectorprefix(a.begin(),a.begin()+s); vector>b=find_p_recursive(prefix,d); if(b.empty())continue; bool ok=true; reps(i,s,a.size()){ if(calc_p_recursive_naive(prefix,b,i).val()!=a[i].val()){ ok=false; break; } } if(ok){ if constexpr(T::mod()==998244353)return calc_p_recursive_fast(prefix,b,K); else return calc_p_recursive_naive(prefix,b,K); } } cerr<<"not found\n"; __builtin_unreachable(); } template std::vectorenumerate_p_recursive(std::vectora,int K){ if(a.size()>K){ a.resize(K); return a; } int n=(int)a.size()-2; for(int d=0;;d++){ int k=(n+2)/(d+2)-1; if(k<=0)break; int s=(n+2)/(d+2)*(d+2)-2; std::vectorprefix(a.begin(),a.begin()+s); std::vector>b=find_p_recursive(prefix,d); if(b.empty())continue; int r=(int)b.size()-1; int deg=(int)b[0].size()-1; std::vectorres(K); for(int i=0;i constexpr int carmichael_constexpr(int n){ if(n==998244353)return 998244352; if(n==1000000007)return 1000000006; if(n<=1)return n; int res=1; int t=0; while(n%2==0){ n/=2; t++; } if(t==2)res=2; else if(t>=3)res=1<<(t-2); for(int i=3;i*i<=n;i++)if(n%i==0){ int c=0; while(n%i==0){ n/=i; c++; } int prod=i-1; for(int j=0;j struct mod_int{ private: static constexpr unsigned int umod=static_cast(m); static constexpr unsigned int car=carmichael_constexpr(m); using uint=unsigned int; using mint=mod_int; uint v; static_assert(mval()<=1)return *this; if constexpr(m%8==1){ mint b=2; while(b.pow((m-1)/2).val()==1)b++; int m2=m-1,e=0; while(m2%2==0)m2>>=1,e++; mint x=this->pow((m2-1)/2); mint y=(*this)*x*x; x*=*this; mint z=b.pow(m2); while(y.val()!=1){ int j=0; mint t=y; while(t.val()!=1)t*=t,j++; z=z.pow(1<<(e-j-1)); x*=z; z*=z; y*=z;e=j; } return x; } else if constexpr(m%8==5){ mint ret=this->pow((m+3)/8); if((ret*ret).val()==this->val())return ret; else return ret*mint::raw(2).pow((m-1)/4); } else{ return this->pow((m+1)/4); } } public: using value_type=uint; mod_int():v(0){} template,std::nullptr_t> =nullptr> mod_int(T a){ a%=m; if(a<0)v=a+umod; else v=a; } template,std::nullptr_t> =nullptr> mod_int(T a):v(a%umod){} static constexpr mint raw(int a){ mint ret; ret.v=a; return ret; } inline uint val()const{return this->v;} static constexpr int mod(){return m;} inline mint &operator+=(const mint &b){ this->v+=b.v; if(this->v>=umod)this->v-=umod; return *this; } inline mint &operator-=(const mint &b){ this->v-=b.v; if(this->v>=umod)this->v+=umod; return *this; } inline mint &operator*=(const mint &b){ this->v=((unsigned long long)this->v*b.v)%umod; return *this; } inline mint &operator/=(const mint &b){ *this*=b.inv(); return *this; } inline mint operator+()const{return *this;} inline mint operator-()const{return mint()-*this;} friend inline mint operator+(const mint &a,const mint &b){return mint(a)+=b;} friend inline mint operator-(const mint &a,const mint &b){return mint(a)-=b;} friend inline mint operator*(const mint &a,const mint &b){return mint(a)*=b;} friend inline mint operator/(const mint &a,const mint &b){return mint(a)/=b;} friend inline bool operator==(const mint &a,const mint &b){return a.val()==b.val();} friend inline bool operator!=(const mint &a,const mint &b){return !(a==b);} inline mint operator++(int){ mint ret=*this; *this+=mint::raw(1); return ret; } inline mint operator--(int){ mint ret=*this; *this-=mint::raw(1); return ret; } mint pow(long long n)const{ mint ret=mint::raw(1),a(*this); while(n){ if(n&1)ret*=a; a*=a; n>>=1; } return ret; } inline mint inv()const{ assert(this->v!=0); return pow(car-1); } std::optionalsqrt()const{ if(this->val()<=1||this->pow((m-1)/2)==1)return std::make_optional(this->sqrt_impl()); else return std::nullopt; } static constexpr unsigned int order(){return car;} friend std::istream &operator>>(std::istream &is,mint &b){ long long a; is>>a; b=mint(a); return is; } friend std::ostream &operator<<(std::ostream &os,const mint &b){ os< struct std::hash>{ std::size_t operator()(mod_intx)const{ return std::hash()(x.val()); } }; using mint998=mod_int<998244353>; using mint107=mod_int<1000000007>; using mint=mint998; mint calc(int n,int i){ int l=i,r=n-i-1; mint res=0; rep(j,l+1)rep(k,r+1){ res+=F::C(l,j)*F::C(r,k)*(j+1)*(k+1); } return res; } void SOLVE(){ int n; cin>>n; vectora(n); cin>>a; vectorcoef(20); rep(i,20){ vectordp(20); rep(j,i,i+20)dp[j-i]=calc(j,i); debug(i,dp); coef[i]=kth_term_p_recursive(dp,n-i); } coef=enumerate_p_recursive(coef,n); mint ans=0; rep(i,n)ans+=a[i]*coef[i]; cout<