namespace GMS { template struct Qring : public vl { using poly = Qring; Qring() : vl(1, 0){} Qring(ll c) : vl(1, c){} Qring(ll c, int n) : vl(n, c){} Qring(const vl& cp) : vl(cp){} ll& operator[](ll idx) { if((unsigned)idx < size()) return vl::operator[](idx); this->resize(idx+1); return vl::operator[](idx); } ll operator[](ll idx) const { if((unsigned)idx < size()) return vl::operator[](idx); return 0LL; } void adjust() { while(size() > T) pop_back(); while(size() > 1 and back() == 0) pop_back(); } void adjust(int n){resize(n, 0);} ll operator()(ll x) { x %= mod; ll ret = 0; for(auto it=rbegin(); it!=rend(); it++) ret = (ret*x+*it)%mod; return ret; } friend poly operator%(const poly& A, int B) // remainder by x^B { poly ret(A); ret.resize(B, 0); return ret; } friend poly operator%(poly&& A, int B) // remainder by x^B { A.resize(B, 0); return A; } friend poly operator+(const poly& A, const poly& B) { int n = max(A.size(), B.size()); poly ret(0, n); fors(i, 0, n-1) ret[i] = (A[i]+B[i])%mod; ret.adjust(); return ret; } friend poly operator+(poly&& A, const poly& B) { int n = B.size(); fors(i, 0, n-1) A[i] = (A[i]+B[i])%mod; A.adjust(); return A; } friend poly operator-(const poly& A) { int n = A.size(); poly ret(0, n); fors(i, 0, n-1) ret[i] = A[i]?mod-A[i]:0; return ret; } friend poly operator-(poly&& A) { int n = A.size(); fors(i, 0, n-1) A[i] = A[i]?mod-A[i]:0; return A; } friend poly operator-(const poly& A, const poly& B) { int n = max(A.size(), B.size()); poly ret(0, n); fors(i, 0, n-1) ret[i] = (mod+A[i]-B[i])%mod; ret.adjust(); return ret; } friend poly operator-(poly&& A, const poly& B) { int n = B.size(); fors(i, 0, n-1) A[i] = (mod+A[i]-B[i])%mod; A.adjust(); return A; } friend poly operator*(ll x, const poly& B) { poly ret(B); x %= mod; for(auto &i : ret) i = (i*x)%mod; ret.adjust(); return ret; } friend poly operator*(const poly& A, const poly& B) { poly ret(conv(A, B)); // ACL : poly ret(atcoder::convolution(A, B)); ret.adjust(); return ret; } //friend poly operator/(const poly& A, const poly& B){return A*inv(B);} friend poly inv(const poly& A){return inv(A, T);} friend poly inv(const poly& A, int t) { assert(A[0] != 0); poly g = pow(A[0], mod-2); int st=1; while(st <= t) { st <<=1; g = (-A%st*g%st+2)*g%st; } g.adjust(t); return g; } friend poly diff(const poly& A) { int n = A.size(); poly ret(0, n-1); forr(i, n-1) ret[i-1] = i*A[i]%mod; return ret; } friend poly inte(const poly& A) { static ll inv[T] = {0, }; int n = A.size(); poly ret(0, n+1); forr(i, n+1) if(inv[i] == 0) inv[i] = pow(i, mod-2); forr(i, n+1) ret[i] = inv[i]*A[i-1]%mod; return ret; } friend poly log(const poly& A){return log(A, T);} friend poly log(const poly& A, int t) { assert(A[0] == 1); poly ret = inte(diff(A) * inv(A, t)%t); ret.adjust(t); return ret; } friend poly exp(const poly& A){return exp(A, T);} friend poly exp(const poly& A, int t) { assert(A[0] == 0); poly g = 1; int st = 1; while(st < t) { st <<= 1; g = (A%st-log(g, st)+1)*g%st; } g.adjust(t); return g; } friend poly pow(const poly& A, ll b, ll t) { poly ret(A); ret.adjust(); if(ret.size() == 1) { ret[0] = pow(ret[0], b); ret.adjust(t); return ret; } ll idx = 0; while(ret[idx] == 0) idx++; if((__int128_t) idx * b >= t) return poly(0, t); ll c = ret[idx]; ll ic = pow(ret[idx], mod-2); poly g; int n = ret.size(); fors(i, idx, n-1) g[i-idx] = ret[i]*ic%mod; g.resize(t-idx*b); g = exp(b * log(g, t-idx*b), t-idx*b); c = pow(c, b); ret = poly(0, t); fors(i, idx*b, t-1) ret[i] = g[i-idx*b] * c % mod; return ret; } //Only just Polynomial, not Qring void rev() { int n=size(); poly& F = *this; for(int i=0; i(fac, mod-2)*n%mod; fore(i, n-1, 0) C[i] = C[i]*fac%mod, fac = fac*i%mod; poly B = C*A; B.resize(n); B.rev(); fore(i, n-1, 0) B[i] = B[i]*facc%mod, facc = facc*i%mod; return B; } friend void calcG(vector& G, int i, int l, int r, const vl& p) { if(l == r) { ll g = p[l]?mod-p[l]:0; G[i] = vl({g, 1}); return; } int mid = (l+r)/2; calcG(G, i*2, l, mid, p); calcG(G, i*2+1, mid+1, r, p); G[i] = G[i*2]*G[i*2+1]; } friend void eval(const vector& G, int i, int l, int r, poly&& F, vl& ret) { if(l == r) { ret[l] = F[0]; return; } int mid=(l+r)/2; eval(G, i*2, l, mid, div_rem(F, G[i*2]), ret); eval(G, i*2+1, mid+1, r, div_rem(F, G[i*2+1]), ret); } friend vl multipoint_eval(const poly& A, const vl& B) { int m = B.size(); vector G(4*m); calcG(G, 1, 0, m-1, B); vl ret(m, 0); eval(G, 1, 0, m-1, div_rem(A, G[1]), ret); return ret; } }; } // namespace GMS const ll mod = 998244353, w = 3, T = 1<<20; using poly = GMS::Qring;