constexpr int MOD = 998244353, INV_2 = (MOD + 1) / 2;
void inc(int &x, int y) {
x += y;
if (x >= MOD) x -= MOD;
}
void dec(int &x, int y) {
x -= y;
if (x < 0) x += MOD;
}
int add(int x, int y) {
x += y;
return x >= MOD ? x - MOD : x;
}
int sub(int x, int y) {
x -= y;
return x < 0 ? x + MOD : x;
}
int neg(int x) { return x ? MOD - x : 0; }
int adj(int x) { return x < 0 ? x + MOD : x; }
int qpow(int x, int y) {
int ret = 1;
for (; y; y >>= 1, x = (ll)x * x % MOD)
if (y & 1) ret = (ll)ret * x % MOD;
return ret;
}
namespace poly {
struct poly_t : vector<int> {
using vector<int>::vector;
};
constexpr int MAXLOG = 18, MAXLEN = 1 << MAXLOG;
int coef[MAXLEN], rev[MAXLEN], inv[MAXLEN + 1];
void init() {
inv[1] = 1;
for (int i = 2; i <= MAXLEN; ++i)
inv[i] = (ll)inv[MOD % i] * (MOD - MOD / i) % MOD;
for (int i = 1; i < MAXLEN; ++i)
rev[i] = rev[i >> 1] >> 1 | (i & 1 ? MAXLEN >> 1 : 0);
int tmp = qpow(3, (MOD - 1) / MAXLEN);
coef[MAXLEN / 2] = 1;
for (int i = MAXLEN / 2 + 1; i < MAXLEN; ++i)
coef[i] = (ll)coef[i - 1] * tmp % MOD;
for (int i = MAXLEN / 2 - 1; i >= 1; --i) coef[i] = coef[i << 1];
}
void ntt(poly_t &f, int v) {
int len = f.size(), d = __lg(len);
for (int i = 1; i < len; ++i) {
int tmp = rev[i] >> (MAXLOG - d);
if (i < tmp) swap(f[i], f[tmp]);
}
for (int i = 1; i < len; i <<= 1) {
for (int j = 0; j < len; j += i << 1) {
for (int k = j; k < j + i; ++k) {
int tmp = (ll)f[k + i] * coef[i + k - j] % MOD;
f[k + i] = sub(f[k], tmp);
inc(f[k], tmp);
}
}
}
if (v == -1) {
int tmp = inv[len];
for (auto &i : f) i = (ll)i * tmp % MOD;
reverse(f.begin() + 1, f.end());
}
}
poly_t &operator+=(poly_t &f, const poly_t &g) {
if (g.size() > f.size()) f.resize(g.size());
for (int i = 0; i < (int)g.size(); ++i) inc(f[i], g[i]);
return f;
}
poly_t &operator-=(poly_t &f, const poly_t &g) {
if (g.size() > f.size()) f.resize(g.size());
for (int i = 0; i < (int)g.size(); ++i) dec(f[i], g[i]);
return f;
}
poly_t &operator*=(poly_t &f, poly_t g) {
if (f.empty() || g.empty()) return f = {};
int tar = f.size() + g.size() - 1, len = (tar == 1 ? 1 : 2 << __lg(tar - 1));
f.resize(len);
g.resize(len);
ntt(f, 1);
ntt(g, 1);
for (int i = 0; i < len; ++i) f[i] = (ll)f[i] * g[i] % MOD;
ntt(f, -1);
f.resize(tar);
return f;
}
poly_t operator+(poly_t f, const poly_t &g) { return f += g; }
poly_t operator-(poly_t f, const poly_t &g) { return f -= g; }
poly_t operator*(poly_t f, const poly_t &g) { return f *= g; }
poly_t inver(const poly_t &f) {
assert(!f.empty() && f[0]);
poly_t ret(f.size());
ret[0] = qpow(f[0], MOD - 2);
for (int i = 1; i < (int)f.size(); i <<= 1) {
poly_t g(i * 2), h(i * 2);
copy(f.begin(), min(f.begin() + i * 2, f.end()), g.begin());
copy(ret.begin(), ret.begin() + i, h.begin());
ntt(g, 1);
ntt(h, 1);
for (int j = 0; j < i * 2; ++j) g[j] = (ll)g[j] * h[j] % MOD;
ntt(g, -1);
fill(g.begin(), g.begin() + i, 0);
ntt(g, 1);
for (int j = 0; j < i * 2; ++j) g[j] = (ll)g[j] * h[j] % MOD;
ntt(g, -1);
for (int j = i, up = min(i * 2, (int)f.size()); j < up; ++j)
ret[j] = neg(g[j]);
}
return ret;
}
poly_t deriv(const poly_t &f) {
if (f.empty()) return {};
poly_t ret(f.size() - 1);
for (int i = 0; i < (int)ret.size(); ++i)
ret[i] = (ll)f[i + 1] * (i + 1) % MOD;
return ret;
}
poly_t integ(const poly_t &f) {
if (f.empty()) return {};
poly_t ret(f.size() + 1);
for (int i = 1; i <= (int)f.size(); ++i) ret[i] = (ll)f[i - 1] * inv[i] % MOD;
return ret;
}
poly_t ln(const poly_t &f) {
assert(!f.empty() && f[0] == 1);
poly_t ret = integ(deriv(f) * inver(f));
ret.resize(f.size());
return ret;
}
poly_t exp(const poly_t &f) {
if (f.empty()) return {1};
assert(!f[0]);
poly_t ret(f.size());
ret[0] = 1;
for (int i = 1; i < (int)f.size(); i <<= 1) {
poly_t g(i * 2), h(i * 2);
copy(ret.begin(), ret.begin() + i, g.begin());
copy(f.begin(), min(f.begin() + i * 2, f.end()), h.begin());
h -= ln(g);
inc(h[0], 1);
ntt(g, 1);
ntt(h, 1);
for (int j = 0; j < i * 2; ++j) g[j] = (ll)g[j] * h[j] % MOD;
ntt(g, -1);
copy(g.begin() + i, g.begin() + min(i * 2, (int)f.size()), ret.begin() + i);
}
ret.resize(f.size());
return ret;
}
poly_t sqrt(const poly_t &f) {
assert(!f.empty() && f[0] == 1);
poly_t ret = {1};
for (int i = 1; i < (int)f.size(); i <<= 1) {
poly_t g(i * 2);
copy(f.begin(), min(f.begin() + i * 2, f.end()), g.begin());
ret.resize(i * 2);
ret += g * inver(ret);
ret.resize(i * 2);
for (auto &j : ret) j = (ll)j * INV_2 % MOD;
}
ret.resize(f.size());
return ret;
}
poly_t pow(poly_t f, int k) {
assert(!f.empty() && f[0] == 1);
f = ln(f);
for (auto &i : f) i = (ll)i * k % MOD;
return exp(f);
}
} // namespace poly
using poly::poly_t;