//#pragma GCC optimize("Ofast") //#pragma GCC target("avx") //#undef LOCAL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using uint = unsigned int; using ll = long long; using ull = unsigned long long; constexpr ll TEN(int n) { return (n == 0) ? 1 : 10 * TEN(n - 1); } template using V = vector; template using VV = V>; #include struct Scanner { int fd = -1; char line[(1 << 15) + 1]; size_t st = 0, ed = 0; void reread() { memmove(line, line + st, ed - st); ed -= st; st = 0; ed += ::read(fd, line + ed, (1 << 15) - ed); line[ed] = '\0'; } bool succ() { while (true) { if (st == ed) { reread(); if (st == ed) return false; } while (st != ed && isspace(line[st])) st++; if (st != ed) break; } if (ed - st <= 50) { bool sep = false; for (size_t i = st; i < ed; i++) { if (isspace(line[i])) { sep = true; break; } } if (!sep) reread(); } return true; } template ::value, int> = 0> bool read_single(T& ref) { if (!succ()) return false; while (true) { size_t sz = 0; while (st + sz < ed && !isspace(line[st + sz])) sz++; ref.append(line + st, sz); st += sz; if (!sz || st != ed) break; reread(); } return true; } template ::value, int> = 0> bool read_single(T& ref) { if (!succ()) return false; bool neg = false; if (line[st] == '-') { neg = true; st++; } ref = T(0); while (isdigit(line[st])) { ref = 10 * ref + (line[st++] & 0xf); } if (neg) ref = -ref; return true; } template bool read_single(V& ref) { for (auto& d : ref) { if (!read_single(d)) return false; } return true; } void read() {} template void read(H& h, T&... t) { bool f = read_single(h); assert(f); read(t...); } Scanner(FILE* fp) : fd(fileno(fp)) {} }; struct Printer { public: template void write() {} template void write(const H& h, const T&... t) { if (F) write_single(' '); write_single(h); write(t...); } template void writeln(const T&... t) { write(t...); write_single('\n'); } Printer(FILE* _fp) : fp(_fp) {} ~Printer() { flush(); } private: static constexpr size_t SIZE = 1 << 15; FILE* fp; char line[SIZE], small[50]; size_t pos = 0; void flush() { fwrite(line, 1, pos, fp); pos = 0; } void write_single(const char& val) { if (pos == SIZE) flush(); line[pos++] = val; } template ::value, int> = 0> void write_single(T val) { if (pos > (1 << 15) - 50) flush(); if (val == 0) { write_single('0'); return; } if (val < 0) { write_single('-'); val = -val; // todo min } size_t len = 0; while (val) { small[len++] = char(0x30 | (val % 10)); val /= 10; } for (size_t i = 0; i < len; i++) { line[pos + i] = small[len - 1 - i]; } pos += len; } void write_single(const string& s) { for (char c : s) write_single(c); } void write_single(const char* s) { size_t len = strlen(s); for (size_t i = 0; i < len; i++) write_single(s[i]); } template void write_single(const V& val) { auto n = val.size(); for (size_t i = 0; i < n; i++) { if (i) write_single(' '); write_single(val[i]); } } }; template struct ModInt { using M = ModInt; static constexpr uint get_mod() { return MD; } const static M G; uint v; ModInt(ll _v = 0) { set_v(uint(_v % MD + MD)); } M& set_v(uint _v) { v = (_v < MD) ? _v : _v - MD; return *this; } explicit operator bool() const { return v != 0; } M operator-() const { return M() - *this; } M operator+(const M& r) const { return M().set_v(v + r.v); } M operator-(const M& r) const { return M().set_v(v + MD - r.v); } M operator*(const M& r) const { return M().set_v(uint(ull(v) * r.v % MD)); } M operator/(const M& r) const { return *this * r.inv(); } M& operator+=(const M& r) { return *this = *this + r; } M& operator-=(const M& r) { return *this = *this - r; } M& operator*=(const M& r) { return *this = *this * r; } M& operator/=(const M& r) { return *this = *this / r; } bool operator==(const M& r) const { return v == r.v; } M pow(ll n) const { M x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; } M inv() const { return pow(MD - 2); } friend ostream& operator<<(ostream& os, const M& r) { return os << r.v; } }; // using Mint = ModInt<998244353>; // template<> const Mint Mint::G = Mint(3); using Mint = ModInt<998244353>; template<> const Mint Mint::G = Mint(3); // bit op int popcnt(uint x) { return __builtin_popcount(x); } int popcnt(ull x) { return __builtin_popcountll(x); } int bsr(uint x) { return 31 - __builtin_clz(x); } int bsr(ull x) { return 63 - __builtin_clzll(x); } int bsf(uint x) { return __builtin_ctz(x); } int bsf(ull x) { return __builtin_ctzll(x); } template void nft(bool type, V& a) { int n = int(a.size()), s = 0; while ((1 << s) < n) s++; assert(1 << s == n); static V ep, iep; while (int(ep.size()) <= s) { ep.push_back(Mint::G.pow(Mint(-1).v / (1 << ep.size()))); iep.push_back(ep.back().inv()); } V b(n); for (int i = 1; i <= s; i++) { int w = 1 << (s - i); Mint base = type ? iep[i] : ep[i], now = 1; for (int y = 0; y < n / 2; y += w) { for (int x = 0; x < w; x++) { auto l = a[y << 1 | x]; auto r = now * a[y << 1 | x | w]; b[y | x] = l + r; b[y | x | n >> 1] = l - r; } now *= base; } swap(a, b); } } template V multiply_nft(const V& a, const V& b) { int n = int(a.size()), m = int(b.size()); if (!n || !m) return {}; if (min(n, m) <= 8) { V ans(n + m - 1); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) ans[i + j] += a[i] * b[j]; return ans; } int lg = 0; while ((1 << lg) < n + m - 1) lg++; int z = 1 << lg; auto a2 = a, b2 = b; a2.resize(z); b2.resize(z); nft(false, a2); nft(false, b2); for (int i = 0; i < z; i++) a2[i] *= b2[i]; nft(true, a2); a2.resize(n + m - 1); Mint iz = Mint(z).inv(); for (int i = 0; i < n + m - 1; i++) a2[i] *= iz; return a2; } // Cooley-Tukey: input -> butterfly -> bit reversing -> output から // bit reversingを抜いたもの 直接使うな template void butterfly(bool type, V& a) { int n = int(a.size()), h = 0; while ((1 << h) < n) h++; assert(1 << h == n); if (n == 1) return; static V snow, sinow; if (snow.empty()) { Mint sep = Mint(1), siep = Mint(1); uint mod = Mint(-1).v; uint di = 4; while (mod % di == 0) { Mint ep = Mint::G.pow(mod / di); Mint iep = ep.inv(); snow.push_back(siep * ep); sinow.push_back(sep * iep); sep *= ep; siep *= iep; di *= 2; } } if (!type) { // fft for (int ph = 1; ph <= h; ph++) { // phase ph: size w -> 2w の FFT, p 並列 int w = 1 << (ph - 1), p = 1 << (h - ph); Mint now = Mint(1); for (int s = 0; s < w; s++) { int offset = s << (h - ph + 1); for (int i = 0; i < p; i++) { auto l = a[i + offset]; auto r = a[i + offset + p] * now; a[i + offset] = l + r; a[i + offset + p] = l - r; } int u = bsf(~uint(s)); now *= snow[u]; } } } else { // ifft for (int ph = h; ph >= 1; ph--) { int w = 1 << (ph - 1), p = 1 << (h - ph); Mint inow = Mint(1); for (int s = 0; s < w; s++) { int offset = s << (h - ph + 1); for (int i = 0; i < p; i++) { auto l = a[i + offset]; auto r = a[i + offset + p]; a[i + offset] = l + r; a[i + offset + p] = (l - r) * inow; } int u = bsf(~uint(s)); inow *= sinow[u]; } } } } template V multiply(const V& a, const V& b) { int n = int(a.size()), m = int(b.size()); if (!n || !m) return {}; if (min(n, m) < 8) { V ans(n + m - 1); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) ans[i + j] += a[i] * b[j]; return ans; } int lg = 0; while ((1 << lg) < n + m - 1) lg++; int z = 1 << lg; auto a2 = a; a2.resize(z); butterfly(false, a2); if (a == b) { for (int i = 0; i < z; i++) a2[i] *= a2[i]; } else { auto b2 = b; b2.resize(z); butterfly(false, b2); for (int i = 0; i < z; i++) a2[i] *= b2[i]; } butterfly(true, a2); a2.resize(n + m - 1); Mint iz = Mint(z).inv(); for (int i = 0; i < n + m - 1; i++) a2[i] *= iz; return a2; } #include #include #include struct Random { private: // Use xoshiro256** // Refereces: http://xoshiro.di.unimi.it/xoshiro256starstar.c static uint64_t rotl(const uint64_t x, int k) { return (x << k) | (x >> (64 - k)); } std::array s; uint64_t next() { const uint64_t result_starstar = rotl(s[1] * 5, 7) * 9; const uint64_t t = s[1] << 17; s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3]; s[2] ^= t; s[3] = rotl(s[3], 45); return result_starstar; } // random choice from [0, upper] uint64_t next(uint64_t upper) { if (!(upper & (upper + 1))) { // b = 00..0011..11 return next() & upper; } int lg = 63 - __builtin_clzll(upper); uint64_t mask = (lg == 63) ? ~0ULL : (1ULL << (lg + 1)) - 1; while (true) { uint64_t r = next() & mask; if (r <= upper) return r; } } public: Random(uint64_t seed = 0) { // Use splitmix64 // Reference: http://xoshiro.di.unimi.it/splitmix64.c for (int i = 0; i < 4; i++) { uint64_t z = (seed += 0x9e3779b97f4a7c15); z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; z = (z ^ (z >> 27)) * 0x94d049bb133111eb; s[i] = z ^ (z >> 31); } } // random choice from [lower, upper] template T uniform(T lower, T upper) { assert(lower <= upper); return T(lower + next(uint64_t(upper - lower))); } bool uniform_bool() { return uniform(0, 1) == 1; } double uniform01() { uint64_t v = next(1ULL << 63); return double(v) / (1ULL << 63); } template std::pair uniform_pair(T lower, T upper) { assert(upper - lower >= 1); T a, b; do { a = uniform(lower, upper); b = uniform(lower, upper); } while (a == b); if (a > b) std::swap(a, b); return {a, b}; } // generate random lower string that length = n std::string lower_string(size_t n) { std::string res = ""; for (size_t i = 0; i < n; i++) { res += uniform('a', 'z'); } return res; } // random shuffle template void shuffle(Iter first, Iter last) { if (first == last) return; // Reference and edit: // cpprefjp - C++日本語リファレンス // (https://cpprefjp.github.io/reference/algorithm/shuffle.html) int len = 1; for (auto it = first + 1; it != last; it++) { len++; int j = uniform(0, len - 1); if (j != len - 1) iter_swap(it, first + j); } } // generate random permutation that length = n template std::vector perm(size_t n) { std::vector idx(n); std::iota(idx.begin(), idx.end(), T(0)); shuffle(idx.begin(), idx.end()); return idx; } template std::vector choice(size_t n, T lower, T upper) { assert(n <= upper - lower + 1); std::set res; while (res.size() < n) res.insert(uniform(lower, upper)); return {res.begin(), res.end()}; } }; Random& global_gen() { static Random gen; return gen; } Random get_random_gen() { return Random(chrono::steady_clock::now().time_since_epoch().count()); } Random& global_runtime_gen() { static Random gen = get_random_gen(); return gen; } template struct Poly { V v; Poly(const V& _v = {}) : v(_v) { shrink(); } void shrink() { while (v.size() && !v.back()) v.pop_back(); } int size() const { return int(v.size()); } D freq(int p) const { return (p < size()) ? v[p] : D(0); } Poly operator+(const Poly& r) const { auto n = max(size(), r.size()); V res(n); for (int i = 0; i < n; i++) res[i] = freq(i) + r.freq(i); return res; } Poly operator-(const Poly& r) const { int n = max(size(), r.size()); V res(n); for (int i = 0; i < n; i++) res[i] = freq(i) - r.freq(i); return res; } Poly operator*(const Poly& r) const { return {multiply(v, r.v)}; } Poly operator*(const D& r) const { int n = size(); V res(n); for (int i = 0; i < n; i++) res[i] = v[i] * r; return res; } Poly operator/(const D &r) const{ return *this * r.inv(); } Poly operator/(const Poly& r) const { if (size() < r.size()) return {{}}; int n = size() - r.size() + 1; return (rev().pre(n) * r.rev().inv(n)).pre(n).rev(n); } Poly operator%(const Poly& r) const { return *this - *this / r * r; } Poly operator<<(int s) const { V res(size() + s); for (int i = 0; i < size(); i++) res[i + s] = v[i]; return res; } Poly operator>>(int s) const { if (size() <= s) return Poly(); V res(size() - s); for (int i = 0; i < size() - s; i++) res[i] = v[i + s]; return res; } Poly& operator+=(const Poly& r) { return *this = *this + r; } Poly& operator-=(const Poly& r) { return *this = *this - r; } Poly& operator*=(const Poly& r) { return *this = *this * r; } Poly& operator*=(const D& r) { return *this = *this * r; } Poly& operator/=(const Poly& r) { return *this = *this / r; } Poly& operator/=(const D &r) {return *this = *this/r;} Poly& operator%=(const Poly& r) { return *this = *this % r; } Poly& operator<<=(const size_t& n) { return *this = *this << n; } Poly& operator>>=(const size_t& n) { return *this = *this >> n; } Poly pre(int le) const { return {{v.begin(), v.begin() + min(size(), le)}}; } Poly rev(int n = -1) const { V res = v; if (n != -1) res.resize(n); reverse(res.begin(), res.end()); return res; } Poly diff() const { V res(max(0, size() - 1)); for (int i = 1; i < size(); i++) res[i - 1] = freq(i) * i; return res; } Poly inte() const { V res(size() + 1); for (int i = 0; i < size(); i++) res[i + 1] = freq(i) / (i + 1); return res; } // f * f.inv() = 1 + g(x)x^m Poly inv(int m) const { Poly res = Poly({D(1) / freq(0)}); for (int i = 1; i < m; i *= 2) { res = (res * D(2) - res * res * pre(2 * i)).pre(2 * i); } return res.pre(m); } Poly exp(int n) const { assert(freq(0) == 0); Poly f({1}), g({1}); for (int i = 1; i < n; i *= 2) { g = (g * 2 - f * g * g).pre(i); Poly q = diff().pre(i - 1); Poly w = (q + g * (f.diff() - f * q)).pre(2 * i - 1); f = (f + f * (*this - w.inte()).pre(2 * i)).pre(2 * i); } return f.pre(n); } Poly log(int n) const { assert(freq(0) == 1); auto f = pre(n); return (f.diff() * f.inv(n - 1)).pre(n - 1).inte(); } Poly sqrt(int n) const { assert(freq(0) == 1); Poly f = pre(n + 1); Poly g({1}); for (int i = 1; i < n; i *= 2) { g = (g + f.pre(2 * i) * g.inv(2 * i)) / 2; } return g.pre(n + 1); } Poly pow_mod(ll n, const Poly& mod) { Poly x = *this, r = {{1}}; while (n) { if (n & 1) r = r * x % mod; x = x * x % mod; n >>= 1; } return r; } friend ostream& operator<<(ostream& os, const Poly& p) { if (p.size() == 0) return os << "0"; for (auto i = 0; i < p.size(); i++) { if (p.v[i]) { os << p.v[i] << "x^" << i; if (i != p.size() - 1) os << "+"; } } return os; } }; template struct MultiEval { using NP = MultiEval*; NP l, r; V que; int sz; Poly mul; MultiEval(const V& _que, int off, int _sz) : sz(_sz) { if (sz <= 100) { que = {_que.begin() + off, _que.begin() + off + sz}; mul = {{1}}; for (auto x : que) mul *= {{-x, 1}}; return; } l = new MultiEval(_que, off, sz / 2); r = new MultiEval(_que, off + sz / 2, sz - sz / 2); mul = l->mul * r->mul; } MultiEval(const V& _que) : MultiEval(_que, 0, int(_que.size())) {} void query(const Poly& _pol, V& res) const { if (sz <= 100) { for (auto x : que) { Mint sm = 0, base = 1; for (int i = 0; i < _pol.size(); i++) { sm += base * _pol.freq(i); base *= x; } res.push_back(sm); } return; } auto pol = _pol % mul; l->query(pol, res); r->query(pol, res); } V query(const Poly& pol) const { V res; query(pol, res); return res; } }; template Poly berlekamp_massey(const V& s) { int n = int(s.size()); V b = {Mint(-1)}, c = {Mint(-1)}; Mint y = Mint(1); for (int ed = 1; ed <= n; ed++) { int l = int(c.size()), m = int(b.size()); Mint x = 0; for (int i = 0; i < l; i++) { x += c[i] * s[ed - l + i]; } b.push_back(0); m++; if (!x) continue; Mint freq = x / y; if (l < m) { // use b auto tmp = c; c.insert(begin(c), m - l, Mint(0)); for (int i = 0; i < m; i++) { c[m - 1 - i] -= freq * b[m - 1 - i]; } b = tmp; y = x; } else { // use c for (int i = 0; i < m; i++) { c[l - 1 - i] -= freq * b[m - 1 - i]; } } } return c; } template Mint sparse_det(const VV& g) { int n = int(g.size()); if (n == 0) return 1; auto rand_v = [&]() { V res(n); for (int i = 0; i < n; i++) { res[i] = Mint(global_gen().uniform(1, Mint::get_mod() - 1)); } return res; }; V c = rand_v(), l = rand_v(), r = rand_v(); // l * mat * r V buf(2 * n); for (int fe = 0; fe < 2 * n; fe++) { for (int i = 0; i < n; i++) { buf[fe] += l[i] * r[i]; } for (int i = 0; i < n; i++) { r[i] *= c[i]; } V tmp(n); for (int i = 0; i < n; i++) { for (auto e : g[i]) { tmp[i] += r[e.to] * e.f; } } r = tmp; } auto u = berlekamp_massey(buf); if (u.size() != n + 1) return sparse_det(g); auto acdet = u.freq(0) * Mint(-1); if (n % 2) acdet *= Mint(-1); if (!acdet) return 0; Mint cdet = 1; for (int i = 0; i < n; i++) cdet *= c[i]; return acdet / cdet; } using MPol = Poly; Scanner sc = Scanner(stdin); Printer pr = Printer(stdout); int main() { int n, q; sc.read(n, q); MPol ans = {{Mint(1)}}; for (int i = 0; i < n; i++) { int a; sc.read(a); MPol f = {{Mint(a - 1), Mint(1)}}; ans = ans * f; } for (int i = 0; i < q; i++) { int b; sc.read(b); pr.writeln(ans.freq(b).v); } return 0; }