using i64 = longlong; using Z = std::complex<longdouble>; constdouble pi = std::acos(-1); std::vector<int> rev; std::vector<Z> roots{(0, 1), (0, 1)};
voiddft(std::vector<Z>& a){ int n = a.size();
if (int(rev.size()) != n) { rev.resize(n); for (int i = 0; i < n; ++i) { rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0); } }
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 = __builtin_ctz(roots.size()); roots.resize(n); while ((1 << k) < n) { Z e(cos(acos(-1) / (1 << k)), sin(acos(-1) / (1 << k))); for (int i = 1 << (k - 1); i < (1 << k); i++) { roots[i << 1] = roots[i]; roots[i << 1 | 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; } } } }
voididft(std::vector<Z>& a){ int n = a.size(); std::reverse(a.begin() + 1, a.end()); dft(a); }
structPoly : public std::vector<i64> { using std::vector<i64>::vector;
Poly() {}
Poly(const std::vector<i64>& a) : std::vector<i64>(a) {}
Poly(const std::initializer_list<i64>& a) : std::vector<i64>(a) {}
template<typename T> T inverse(T a, T b){ T u = 0, v = 1; while (a != 0) { T t = b / a; b -= t * a; std::swap(a, b); u -= t * v; std::swap(u, v); } assert(b == 1); return u; }
template<typename T> T power(T a, int b){ T ans = 1; for (; b; a *= a, b >>= 1) { if (b & 1)ans *= a; } return ans; }
template<int Mod> classModular { public: using Type = int;
template<typename U> static Type norm(U &x){ Type v; if (-Mod <= x && x < Mod) v = static_cast<Type>(x); else v = static_cast<Type>(x % Mod); if (v < 0) v += Mod; return v; }
constexprint mod = 998244353; using Z = Modular<mod>;
std::vector<int> rev; std::vector<Z> roots{0, 1};
voiddft(std::vector<Z> &a){ int n = a.size();
if (int(rev.size()) != n) { rev.resize(n); for (int i = 0; i < n; ++i) { rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0); } }
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 = __builtin_ctz(roots.size()); roots.resize(n); while ((1 << k) < n) { Z e = power(Z(3), (mod - 1) >> (k + 1)); for (int i = 1 << (k - 1); i < (1 << k); i++) { roots[i << 1] = roots[i]; roots[i << 1 | 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; } } } }
voididft(std::vector<Z> &a){ int n = a.size(); std::reverse(a.begin() + 1, a.end()); dft(a); }
structPoly : public std::vector<Z> { using std::vector<Z>::vector;
Poly exp(int m)const{ Poly x{Z(1)}; int k = 1; while (k < m) { k *= 2; x = (x * (Poly{Z(1)} - x.log(k) + modxk(k))).modxk(k); } return x.modxk(m); }
Poly pow(int k, int m)const{ int i = 0; while (i < size() && (*this)[i].val() == 0) { i++; } if (i == size() || 1LL * i * k >= m) { returnPoly(m); } Z v = (*this)[i]; Poly f = divxk(i) * (v.inv().val()); return (f.log(m - i * k) * k).exp(m - i * k).mulxk(i * k) * power(v, k).val(); }
Poly sqrt(int m)const{ Poly x{Z(1)}; int k = 1; while (k < m) { k *= 2; x = (x + (modxk(k) * x.inv(k)).modxk(k)) * ((mod + 1) / 2); } return x.modxk(m); }
Poly mulT(Poly b)const{ if (b.empty()) { return {}; } int n = b.size(); std::reverse(b.begin(), b.end()); return ((*this) * b).divxk(n - 1); }
std::vector<Z> eval(std::vector<Z> x)const{ if (empty()) { returnPoly(x.size()); } constint n = std::max(int(x.size()), (int) size()); std::vector<Poly> q(4 * n); std::vector<Z> ans(x.size()); x.resize(n); std::function<void(int, int, int)> 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<void(int, int, int, const Poly &)> 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; } };
template<class T> T inverse(T a, T b){ T u = 0, v = 1; while (a != 0) { T t = b / a; b -= t * a; std::swap(a, b); u -= t * v; std::swap(u, v); } assert(b == 1); return u; }
template<class T> T power(T a, i64 b){ T ret = 1; for (; b; b >>= 1, a = a * a)if (b & 1)ret = ret * a; return ret; }
intnorm(int x){ return x < 0 ? x += P : x >= P ? x -= P : x; }
structModInt { int a;
ModInt(int a = 0) : a(norm(a)) {} // assume a <= 2P ModInt(i64 a) : a(norm(a % P)) {}
using Z = ModInt; std::vector<int> rev; std::vector<Z> roots{0, 1};
voiddft(std::vector<Z>& a){ int n = a.size();
if (int(rev.size()) != n) { rev.resize(n); for (int i = 0; i < n; ++i) { rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0); } }
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 = __builtin_ctz(roots.size()); 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[i << 1] = roots[i]; roots[i << 1 | 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; } } } }
voididft(std::vector<Z>& a){ int n = a.size(); std::reverse(a.begin() + 1, a.end()); dft(a); }
structPoly : public std::vector<Z> { using std::vector<Z>::vector;
Poly() = default;
explicitPoly(const std::vector<Z>& a) : vector(a) {}
Poly exp(int m)const{ Poly x{Z(1)}; int k = 1; while (k < m) { k *= 2; x = (x * (Poly{Z(1)} - x.log(k) + modxk(k))).modxk(k); } return x.modxk(m); }
Poly pow(int k, int m)const{ int i = 0; while (i < size() && (*this)[i].val() == 0) { i++; } if (i == size() || 1LL * i * k >= m) { returnPoly(m); } Z v = (*this)[i]; Poly f = divxk(i) * (v.inv().val()); return (f.log(m - i * k) * k).exp(m - i * k).mulxk(i * k) * power(v, k).val(); }
Poly sqrt(int m)const{ Poly x{Z(1)}; int k = 1; while (k < m) { k *= 2; x = (x + (modxk(k) * x.inv(k)).modxk(k)) * ((P + 1) / 2); } return x.modxk(m); }
Poly mulT(Poly b)const{ if (b.empty()) { return {}; } int n = b.size(); std::reverse(b.begin(), b.end()); return ((*this) * b).divxk(n - 1); }
std::vector<Z> eval(std::vector<Z> x)const{ if (empty()) { returnPoly(x.size()); } constint n = std::max(int(x.size()), (int) size()); std::vector<Poly> q(4 * n); std::vector<Z> ans(x.size()); x.resize(n); std::function<void(int, int, int)> 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<void(int, int, int, const Poly&)> 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; } };
template<typename T> T inverse(T a, T b){ T u = 0, v = 1; while (a != 0) { T t = b / a; b -= t * a; std::swap(a, b); u -= t * v; std::swap(u, v); } assert(b == 1); return u; }
template<typename T> T power(T a, longlong b, int mod){ T ans = 1; for (; b; a = 1ll * a * a % mod, b >>= 1) { if (b & 1)ans = 1ll * ans * a % mod; } return ans; }
int mod; using Z = std::complex<longdouble>; using i64 = longlong; constdouble pi = std::acos(-1); std::vector<int> rev; std::vector<Z> roots{(0, 1), (0, 1)};
intgetsz(int x){ int sz = 1; while (sz < x)sz *= 2; return sz; }
voiddft(std::vector<Z>& a){ int n = a.size();
if (int(rev.size()) != n) { rev.resize(n); for (int i = 0; i < n; ++i) { rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? n >> 1 : 0); } }
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 = __builtin_ctz(roots.size()); roots.resize(n); while ((1 << k) < n) { Z e(cos(acos(-1) / (1 << k)), sin(acos(-1) / (1 << k))); for (int i = 1 << (k - 1); i < (1 << k); i++) { roots[i << 1] = roots[i]; roots[i << 1 | 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; } } } }
voididft(std::vector<Z>& a){ int n = a.size(); std::reverse(a.begin() + 1, a.end()); dft(a); }
template<typename U> static U norm(U& x, int Mod){ if (-Mod <= x && x < Mod) x = static_cast<U>(x); else x = static_cast<U>(x % Mod); if (x < 0) x += Mod; return x; }
structPoly : public std::vector<i64> { using std::vector<i64>::vector;
Poly deriv()const{ if (empty()) { return {}; } Poly res(size() - 1); for (int i = 0; i < size() - 1; ++i) { res[i] = (i + 1) * (*this)[i + 1] % mod; } return res; }
Poly integr()const{ Poly res(size() + 1); for (int i = 0; i < size(); ++i) { res[i + 1] = (*this)[i] * power(i + 1, mod - 2, mod); } return res; }
friend Poly operator *(const Poly& x, const Poly& y) { if (x.empty() || y.empty())return {}; Poly a(x), b(y); int len = a.size() + b.size() - 1, n = getsz(len); vector<Z> f(n), g(n), p(n), q(n); for (int i = 0; i < a.size(); i++) f[i] = Z(a[i] >> 15, a[i] & 0x7fff); for (int i = 0; i < b.size(); i++) g[i] = Z(b[i] >> 15, b[i] & 0x7fff); dft(f), dft(g); for (int i = 0; i < n; ++i) { int r = (n - i) & (n - 1); p[i] = Z(0.5 * (f[i].real() + f[r].real()), 0.5 * (f[i].imag() - f[r].imag())) * g[i]; q[i] = Z(0.5 * (f[i].imag() + f[r].imag()), 0.5 * (f[r].real() - f[i].real())) * g[i]; } idft(p), idft(q); for (int i = 0; i < n; ++i)p[i] /= n, q[i] /= n; a.resize(len); for (int i = 0; i < len; i++) { longlong X, Y, Z, W; X = p[i].real() + 0.5, Y = p[i].imag() + 0.5; Z = q[i].real() + 0.5, W = q[i].imag() + 0.5; a[i] = ((X % mod << 30) + ((Y + Z) % mod << 15) + W) % mod; } return a; }
Poly inv(int m)const{ Poly x{(power((*this)[0], mod - 2, mod))}; int k = 1; while (k < m) { k <<= 1; x = (x * (Poly{2} - modxk(k) * x)).modxk(k); } return x; } };