#pragma GCC optimize("Ofast") #pragma GCC target("avx2") #include #include #include using namespace std; using namespace atcoder; using mint=atcoder::static_modint<998244353>; #define rep(i,a,b) for(int i=(a);i<(b);++i) #define all(n) (n).begin(),(n).end() arrayfact; using lint=long long; istream& operator>>(istream& in,mint& y){ long long x; in>>x; y=mint(x); return in; } ostream& operator>>(ostream& out,const mint& y){ out<; int sz(const poly&x){return x.size();} poly shrink(poly x){ while(sz(x)>=1&&x.back().val()==0)x.pop_back(); return x; } poly pre(const poly&x,int n){ auto res=x; res.resize(n); return res; } poly operator+(const poly& x,const poly& y){ poly res(max(x.size(),y.size())); rep(i,0,x.size())res[i]+=x[i]; rep(i,0,y.size())res[i]+=y[i]; return res; } poly operator-(const poly& x){ poly res(x.size()); rep(i,0,x.size())res[i]=-x[i]; return res; } poly operator-(const poly&x,const poly&y){ return x+(-y); } poly operator*(const poly&x,const poly&y){ return atcoder::convolution(x,y); } poly& operator+=(poly& x,const poly& y){ return x=(x+y); } poly& operator-=(poly& x,const poly& y){ return x=(x-y); } poly& operator*=(poly& x,const poly& y){ return x=(x*y); } istream& operator>>(istream& in,poly& y){ int n=sz(y); rep(i,0,n)in>>y[i]; return in; } ostream& operator<<(ostream& out,const poly& y){ int n=sz(y); rep(i,0,n){ if(i)out<<' '; out< divmod(const poly&a,const poly& b){ assert(!b.empty()); if(b.back().val()==0)return divmod(a,shrink(b)); if(a.empty())return make_pair(poly{},poly{}); if(a.back().val()==0)return divmod(shrink(a),b); int n=max(0,sz(a)-sz(b)+1); if(n==0)return make_pair(poly{},a); auto c=a; auto d=b; reverse(c.begin(),c.end()); reverse(d.begin(),d.end()); d.resize(n); c*=inv(d); c.resize(n); reverse(c.begin(),c.end()); return make_pair(c,pre(a-c*b,(int)b.size()-1)); } poly multipoint_evalution(const poly&a,const poly&b){ int n=b.size(); vectorv(n*2); rep(i,0,n){ v[i+n]=poly{-mint(b[i]),mint(1)}; } for(int i=n-1;i>=1;--i){ v[i]=v[i*2]*v[i*2+1]; } poly ans(n); v[0]=a; rep(i,1,n*2){ v[i]=divmod(v[i/2],v[i]).second; if(i>=n)ans[i-n]=v[i][0]; } return ans; } vector shift(vectora,int t,int m=-1){ int n=a.size(); if(m==-1){ return shift(a,t,n); }else if(m==0){ return vector(); }else if(mn){ int z=max(n,m-n); auto p=shift(a,t,z); auto q=shift(a,t+z,n); p.insert(p.end(),q.begin(),q.end()); p.resize(m); return p; } //前計算 vectorfact(n,1),expx(n,1),expr(n,1),v(n,1); rep(i,1,n)fact[i]=fact[i-1]*i; expx[n-1]=fact[n-1].inv(); for(int i=n-2;i>=0;--i)expx[i]=expx[i+1]*(i+1); rep(i,0,n)expr[i]=expx[i]*(i%2?-1:1); rep(i,1,n)v[i]=v[i-1]*(t-i+1); rep(i,0,n)v[i]*=expx[i]; // 下降冪表示に変換 rep(i,0,n)a[i]*=expx[i]; a=atcoder::convolution(a,expr); a.resize(n); // shift rep(i,0,n)a[i]*=fact[i]; reverse(all(a)); a=atcoder::convolution(a,v); a.resize(n); reverse(all(a)); rep(i,0,n)a[i]*=expx[i]; // 標本点に変換 a=atcoder::convolution(a,expx); a.resize(n); rep(i,0,n)a[i]*=fact[i]; return a; } template array mul(const array& a,const array& b){ arrayres; res.fill(T()); rep(i,0,2)rep(k,0,2)rep(j,0,2){ res[i+k*2]+=a[i+j*2]*b[j+k*2]; } return res; } array,4> shift(array,4> a){ int n=a[0].size(); // rep(t,0,1)rep(j,0,n)cout<,4>b; rep(i,0,4)b[i].resize(n*2); rep(j,0,n*2){ auto c=mul(array{a[0][j*2],a[1][j*2],a[2][j*2],a[3][j*2]},array{a[0][j*2+1],a[1][j*2+1],a[2][j*2+1],a[3][j*2+1]}); rep(i,0,4)b[i][j]=c[i]; } return b; } void solve2(){ lint n,k; cin>>n>>k; if(k>=mint::mod()){ cout<<0<,4>a=array,4>{vector{mint(n)*2,mint(n-1)*2,mint(n-2)*2},vector{mint(0),mint(n),mint(n*2-1)},vector(3,mint(1)),vector(3,mint(0))}; lint i=1; for(;i*i*3 ans=array{mint(1),mint(0),mint(0),mint(1)}; // auto ans2=ans; for(;(j+1)*i{a[0][j],a[1][j],a[2][j],a[3][j]}); } auto get=[&](lint k){ return array{mint(n-k)*2,mint(k)*(n*2-k+1)/2,mint(1),mint(0)}; }; // cerr<>v(n); rep(i,0,n)cin>>v[i].second>>v[i].first; auto v2=v; sort(v.begin(),v.end()); int sz=1; while(szarray { return array{poly{-mint(k*2),mint(2)},poly{mint(-k*(k-1)/2),mint(k)},poly{mint(1)},poly{mint(0)}}; }; auto prod=[&](auto prod,const vector>& x)->array { if(x.size()==0)return array{poly{mint(1)},poly{mint(0)},poly{mint(0)},poly{mint(1)}}; if(x.size()==1)return x[0]; return mul(prod(prod,vector(x.begin(),x.begin()+x.size()/2)),prod(prod,vector(x.begin()+x.size()/2,x.end()))); }; vectordiv(sz*2,poly{mint(1)}); const auto one=array{poly{mint(1)},poly{mint(0)},poly{mint(0)},poly{mint(1)}}; vector>res(sz*2,one); int tmp2=0; rep(i,0,n){ rep(j,i?v[i-1].first:0,v[i].first){ res[sz+tmp2]=get(j); tmp2++; } div[sz+tmp2]=poly{-mint(v[i].second),mint(1)}; tmp2++; } for(int i=sz-1;i>=1;--i){ res[i]=mul(res[i*2],res[i*2+1]); } for(int i=sz-1;i>=1;--i){ div[i]=div[i*2]*div[i*2+1]; } vector ans(n); map,mint> ans2; int cnt=0; auto dfs=[&](auto dfs,int i,arraynow)->void { rep(j,0,4)now[j]=divmod(now[j],div[i]).second; if(cnt=2)res[i]=mul(res[i/2],res[i]); // rep(j,0,4){ // res[i][j]=divmod(res[i][j],div[i]).second; // } // if(i>=sz&&i>t; if(t>5){ solve1(t); return 0; } while(t--){ solve2(); } }