#include #include #include #include #include #include #include using namespace std; constexpr long long P = 998244353; const long long mod = P; using i64 = long long; #define ll long long ll start = 0; inline long long get_time() { return chrono::duration_cast(chrono::steady_clock().now().time_since_epoch()).count(); } inline ll get_delta() { ll k = get_time() - start; start += k; return k; } inline void delta() { cout << get_delta() << "\n"; } inline long long mul(long long a, long long b) { return a * b % P; } // assume -P <= x < 2P inline int norm(int x) { if (x < 0) { x += P; } if (x >= P) { x -= P; } return x; } inline long long bp(long long a, int b) { long long res = 1; for (; b; b /= 2, a = mul(a, a)) { if (b % 2) { res = mul(res, a); } } return res; } template inline T power(T a, int b) { T res = 1; for (; b; b /= 2, a *= a) { if (b % 2) { res *= a; } } return res; } struct Z { int x; inline Z(int x = 0) : x(norm(x)) {} int val() const { return x; } inline Z operator-() const { return Z(norm(P - x)); } inline Z inv() const { return power(*this, P - 2); } inline Z& operator*=(const Z& rhs) { x = i64(x) * rhs.x % P; return *this; } inline Z& operator+=(const Z& rhs) { x = norm(x + rhs.x); return *this; } inline Z& operator-=(const Z& rhs) { x = norm(x - rhs.x); return *this; } inline Z& operator/=(const Z& rhs) { return *this *= rhs.inv(); } inline friend Z operator*(const Z& lhs, const Z& rhs) { Z res = lhs; res *= rhs; return res; } inline friend Z operator+(const Z& lhs, const Z& rhs) { Z res = lhs; res += rhs; return res; } inline friend Z operator-(const Z& lhs, const Z& rhs) { Z res = lhs; res -= rhs; return res; } inline friend Z operator/(const Z& lhs, const Z& rhs) { Z res = lhs; res /= rhs; return res; } }; std::vector rev; std::vector roots{ 0, 1 }; inline void dft(std::vector& a) { int n = a.size(); if (int(rev.size()) != n) { int k = 0; while ((1 << k) < n) k++; k--; rev.resize(n); for (int i = 0; i < n; i++) { rev[i] = rev[i >> 1] >> 1 | (i & 1) << k; } } for (int i = 0; i < n; i++) { if (rev[i] < i) { std::swap(a[i], a[rev[i]]); } } if (int(roots.size()) < n) { int k = 0; while ((1 << k) < roots.size()) k++; roots.resize(n); while ((1 << k) < n) { Z e = power(Z(3), (P - 1) >> (k + 1)); for (int i = 1 << (k - 1); i < (1 << k); i++) { roots[2 * i] = roots[i]; roots[2 * i + 1] = roots[i] * e; } k++; } } for (int k = 1; k < n; k *= 2) { for (int i = 0; i < n; i += 2 * k) { for (int j = 0; j < k; j++) { Z u = a[i + j]; Z v = a[i + j + k] * roots[k + j]; a[i + j] = u + v; a[i + j + k] = u - v; } } } } inline void idft(std::vector& a) { int n = a.size(); std::reverse(a.begin() + 1, a.end()); dft(a); Z inv = (1 - P) / n; for (int i = 0; i < n; i++) { a[i] *= inv; } } vector longtoZ(vector a); struct Poly { std::vector a; Poly() {} Poly(const std::vector& a) : a(a) {} Poly(const std::vector& a) : a(longtoZ(a)) {} Poly(const std::initializer_list& a) : a(a) {} inline int size() const { return a.size(); } inline void resize(int n) { a.resize(n); } inline Z operator[](int idx) const { if (idx < 0 || idx >= size()) { return 0; } return a[idx]; } inline Z& operator[](int idx) { return a[idx]; } inline Poly mulxk(int k) const { auto b = a; b.insert(b.begin(), k, 0); return Poly(b); } inline Poly modxk(int k) const { k = std::min(k, size()); return Poly(std::vector(a.begin(), a.begin() + k)); } inline Poly divxk(int k) const { if (size() <= k) { return Poly(); } return Poly(std::vector(a.begin() + k, a.end())); } inline friend Poly operator+(const Poly& a, const Poly& b) { std::vector res(std::max(a.size(), b.size())); for (int i = 0; i < int(res.size()); i++) { res[i] = a[i] + b[i]; } return Poly(res); } inline friend Poly operator-(const Poly& a, const Poly& b) { std::vector res(std::max(a.size(), b.size())); for (int i = 0; i < int(res.size()); i++) { res[i] = a[i] - b[i]; } return Poly(res); } inline friend Poly operator*(Poly a, Poly b) { if (a.size() == 0 || b.size() == 0) { return Poly(); } int sz = 1, tot = a.size() + b.size() - 1; while (sz < tot) sz *= 2; a.a.resize(sz); b.a.resize(sz); dft(a.a); dft(b.a); for (int i = 0; i < sz; ++i) { a.a[i] = a[i] * b[i]; } idft(a.a); a.resize(tot); return a; } inline friend Poly operator*(Z a, Poly b) { for (int i = 0; i < int(b.size()); i++) { b[i] *= a; } return b; } inline friend Poly operator*(Poly a, Z b) { for (int i = 0; i < int(a.size()); i++) { a[i] *= b; } return a; } inline Poly& operator+=(Poly b) { return (*this) = (*this) + b; } inline Poly& operator-=(Poly b) { return (*this) = (*this) - b; } inline Poly& operator*=(Poly b) { return (*this) = (*this) * b; } inline Poly inv(int m) const { Poly x{ a[0].inv() }; int k = 1; while (k < m) { k *= 2; x = (x * (Poly{ 2 } - modxk(k) * x)).modxk(k); } return x.modxk(m); } inline Poly mulT(Poly b) const { if (b.size() == 0) { return Poly(); } int n = b.size(); std::reverse(b.a.begin(), b.a.end()); return ((*this) * b).divxk(n - 1); } inline std::vector eval(std::vector x) const { if (size() == 0) { return std::vector(x.size(), 0); } if (size() < 450) { vector ans(x.size(), 0); for (int i = 0; i < x.size(); i++) { for (int j = size() - 1; j >= 0; j--) { ans[i] *= x[i]; ans[i] += a[j]; } } return ans; } const int n = std::max(int(x.size()), size()); std::vector q(4 * n); std::vector ans(x.size()); x.resize(n); std::function build = [&](int p, int l, int r) { if (r - l == 1) { q[p] = Poly{ 1, -x[l] }; } else { int m = (l + r) / 2; build(2 * p, l, m); build(2 * p + 1, m, r); q[p] = q[2 * p] * q[2 * p + 1]; } }; build(1, 0, n); std::function work = [&](int p, int l, int r, const Poly& num) { if (r - l == 1) { if (l < int(ans.size())) { ans[l] = num[0]; } } else { int m = (l + r) / 2; work(2 * p, l, m, num.mulT(q[2 * p + 1]).modxk(m - l)); work(2 * p + 1, m, r, num.mulT(q[2 * p]).modxk(r - m)); } }; work(1, 0, n, mulT(q[1].inv(n))); return ans; } }; inline vector longtoZ(vector a) { vector b; for (auto& i : a) b.push_back(Z(i)); return b; } inline vector Ztolong(vector a) { vector b; for (auto& i : a) b.push_back(i.x); return b; } vector mult(vector a, vector b) { Poly p1(a); Poly p2(b); return Ztolong((p1 * p2).a); } vector eval(vector a, vector x) { return Ztolong(Poly(a).eval(longtoZ(x))); }