#pragma GCC optimize("Ofast") #include using namespace std; typedef long long int ll; typedef unsigned long long int ull; mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count()); ll myRand(ll B) { return (ull)rng() % B; } inline double time() { return static_cast(chrono::duration_cast(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9; } template struct static_modint { using mint = static_modint; int x; static_modint() : x(0) {} static_modint(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {} mint& operator+=(const mint& rhs) { if ((x += rhs.x) >= mod) x -= mod; return *this; } mint& operator-=(const mint& rhs) { if ((x += mod - rhs.x) >= mod) x -= mod; return *this; } mint& operator*=(const mint& rhs) { x = (int) (1LL * x * rhs.x % mod); return *this; } mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); } mint pow(long long n) const { mint _x = *this, r = 1; while (n) { if (n & 1) r *= _x; _x *= _x; n >>= 1; } return r; } mint inv() const { return pow(mod - 2); } mint operator+() const { return *this; } mint operator-() const { return mint() - *this; } friend mint operator+(const mint& lhs, const mint& rhs) { return mint(lhs) += rhs; } friend mint operator-(const mint& lhs, const mint& rhs) { return mint(lhs) -= rhs; } friend mint operator*(const mint& lhs, const mint& rhs) { return mint(lhs) *= rhs; } friend mint operator/(const mint& lhs, const mint& rhs) { return mint(lhs) /= rhs; } friend bool operator==(const mint& lhs, const mint& rhs) { return lhs.x == rhs.x; } friend bool operator!=(const mint& lhs, const mint& rhs) { return lhs.x != rhs.x; } friend ostream &operator<<(ostream &os, const mint &p) { return os << p.x; } friend istream &operator>>(istream &is, mint &a) { int64_t t; is >> t; a = static_modint(t); return (is); } }; const unsigned int mod = 998244353; using modint = static_modint; modint mod_pow(ll n, ll x) { return modint(n).pow(x); } modint mod_pow(modint n, ll x) { return n.pow(x); } template struct Comination { vector p, invp; Comination(int sz) : p(sz+1), invp(sz+1) { p[0] = 1; for (int i = 1; i <= sz; ++i) { p[i] = p[i-1] * i; } invp[sz] = p[sz].inv(); for (int i = sz-1; i >= 0; --i) { invp[i] = invp[i+1] * (i+1); } } T comb(int n, int r) { if (r < 0 or n < r) return 0; return p[n]*invp[n-r]*invp[r]; } T big_comb(T n, int r) { T res = invp[r]; for (int i = 0; i < r; ++i) { res *= (n-i); } return res; } }; using Comb = Comination; Comb p(1<<20); constexpr long long safe_mod(long long x, long long m) { x %= m; if (x < 0) x += m; return x; } constexpr long long pow_mod_constexpr(long long x, long long n, int m) { if (m == 1) return 0; unsigned int _m = (unsigned int)(m); unsigned long long r = 1; unsigned long long y = safe_mod(x, m); while (n) { if (n & 1) r = (r * y) % _m; y = (y * y) % _m; n >>= 1; } return r; } constexpr int primitive_root_constexpr(int m) { if (m == 2) return 1; if (m == 167772161) return 3; if (m == 469762049) return 3; if (m == 754974721) return 11; if (m == 998244353) return 3; int divs[20] = {}; divs[0] = 2; int cnt = 1; int x = (m - 1) / 2; while (x % 2 == 0) x /= 2; for (int i = 3; (long long)(i)*i <= x; i += 2) { if (x % i == 0) { divs[cnt++] = i; while (x % i == 0) { x /= i; } } } if (x > 1) { divs[cnt++] = x; } for (int g = 2;; g++) { bool ok = true; for (int i = 0; i < cnt; i++) { if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) { ok = false; break; } } if (ok) return g; } } template constexpr int primitive_root = primitive_root_constexpr(m); constexpr int countr_zero_constexpr(unsigned int n) { int x = 0; while (!(n & (1 << x))) x++; return x; } struct fft_info { int g; static constexpr int rank2 = countr_zero_constexpr(mod - 1); std::array root; // root[i]^(2^i) == 1 std::array iroot; // root[i] * iroot[i] == 1 std::array rate2; std::array irate2; std::array rate3; std::array irate3; fft_info() { g = primitive_root; root[rank2] = (mod_pow(g, (mod - 1) >> rank2)); iroot[rank2] = root[rank2].inv(); for (int i = rank2 - 1; i >= 0; i--) { root[i] = root[i + 1] * root[i + 1]; iroot[i] = iroot[i + 1] * iroot[i + 1]; } { modint prod = 1, iprod = 1; for (int i = 0; i <= rank2 - 2; i++) { rate2[i] = root[i + 2] * prod; irate2[i] = iroot[i + 2] * iprod; prod *= iroot[i + 2]; iprod *= root[i + 2]; } } { modint prod = 1, iprod = 1; for (int i = 0; i <= rank2 - 3; i++) { rate3[i] = root[i + 3] * prod; irate3[i] = iroot[i + 3] * iprod; prod *= iroot[i + 3]; iprod *= root[i + 3]; } } } }; void butterfly(vector &a) { int n = int(a.size()); int h = __builtin_ctz(n); static const fft_info info; int len = 0; // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed while (len < h) { if (h - len == 1) { int pp = 1 << (h - len - 1); modint rot = 1; for (int s = 0; s < (1 << len); s++) { int offset = s << (h - len); for (int i = 0; i < pp; i++) { auto l = a[i + offset]; auto r = a[i + offset + pp] * rot; a[i + offset] = l + r; a[i + offset + pp] = l - r; } if (s + 1 != (1 << len)) rot *= info.rate2[__builtin_ctz(~(unsigned int)(s))]; } len++; } else { // 4-base int pp = 1 << (h - len - 2); modint rot = 1, imag = info.root[2]; for (int s = 0; s < (1 << len); s++) { modint rot2 = rot * rot; modint rot3 = rot2 * rot; int offset = s << (h - len); for (int i = 0; i < pp; i++) { auto mod2 = 1ULL * mod * mod; auto a0 = 1ULL * a[i + offset].x; auto a1 = 1ULL * a[i + offset + pp].x * rot.x; auto a2 = 1ULL * a[i + offset + 2 * pp].x * rot2.x; auto a3 = 1ULL * a[i + offset + 3 * pp].x * rot3.x; auto a1na3imag = 1ULL * modint(a1 + mod2 - a3).x * imag.x; auto na2 = mod2 - a2; a[i + offset] = a0 + a2 + a1 + a3; a[i + offset + 1 * pp] = a0 + a2 + (2 * mod2 - (a1 + a3)); a[i + offset + 2 * pp] = a0 + na2 + a1na3imag; a[i + offset + 3 * pp] = a0 + na2 + (mod2 - a1na3imag); } if (s + 1 != (1 << len)) rot *= info.rate3[__builtin_ctz(~(unsigned int)(s))]; } len += 2; } } } void butterfly_inv(vector &a) { int n = int(a.size()); int h = __builtin_ctz(n); static const fft_info info; int len = h; // a[i, i+(n>>len), i+2*(n>>len), ..] is transformed while (len) { if (len == 1) { int pp = 1 << (h - len); modint irot = 1; for (int s = 0; s < (1 << (len - 1)); s++) { int offset = s << (h - len + 1); for (int i = 0; i < pp; i++) { auto l = a[i + offset]; auto r = a[i + offset + pp]; a[i + offset] = l + r; a[i + offset + pp] = (unsigned long long)(mod + l.x - r.x) * irot.x; } if (s + 1 != (1 << (len - 1))) irot *= info.irate2[__builtin_ctz(~(unsigned int)(s))]; } len--; } else { // 4-base int pp = 1 << (h - len); modint irot = 1, iimag = info.iroot[2]; for (int s = 0; s < (1 << (len - 2)); s++) { modint irot2 = irot * irot; modint irot3 = irot2 * irot; int offset = s << (h - len + 2); for (int i = 0; i < pp; i++) { auto a0 = 1ULL * a[i + offset + 0 * pp].x; auto a1 = 1ULL * a[i + offset + 1 * pp].x; auto a2 = 1ULL * a[i + offset + 2 * pp].x; auto a3 = 1ULL * a[i + offset + 3 * pp].x; auto a2na3iimag = 1ULL * modint((mod + a2 - a3) * iimag.x).x; a[i + offset] = a0 + a1 + a2 + a3; a[i + offset + 1 * pp] = (a0 + (mod - a1) + a2na3iimag) * irot.x; a[i + offset + 2 * pp] = (a0 + a1 + (mod - a2) + (mod - a3)) * irot2.x; a[i + offset + 3 * pp] = (a0 + (mod - a1) + (mod - a2na3iimag)) * irot3.x; } if (s + 1 != (1 << (len - 2))) irot *= info.irate3[__builtin_ctz(~(unsigned int)(s))]; } len -= 2; } } } vector convolution_naive(const vector& a, const vector& b) { int n = int(a.size()), m = int(b.size()); vector res(n + m - 1); if (n < m) { for (int j = 0; j < m; ++j) { for (int i = 0; i < n; ++i) { res[i + j] += a[i] * b[j]; } } } else { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { res[i + j] += a[i] * b[j]; } } } return res; } vector convolution_fft(vector& a, vector& b) { int n = int(a.size()), m = int(b.size()); int z = 1; while (z < n + m - 1) z *= 2; a.resize(z); butterfly(a); b.resize(z); butterfly(b); for (int i = 0; i < z; ++i) { a[i] *= b[i]; } butterfly_inv(a); a.resize(n + m - 1); modint iz = modint(z).inv(); for (int i = 0; i < n + m - 1; i++) a[i] *= iz; return a; } template vector convolution(const vector& a, const vector& b) { int n = int(a.size()), m = int(b.size()); if (!n or !m) return {}; int z = 1; while (z < n + m - 1) z *= 2; assert((mod - 1) % z == 0); vector a2(n), b2(m); for (int i = 0; i < n; ++i) { a2[i] = modint(a[i]); } for (int i = 0; i < m; ++i) { b2[i] = modint(b[i]); } vector c(n + m - 1); vector c2; if (min(n,m) <= 60) c2 = convolution_naive(a2, b2); else c2 = convolution_fft(a2, b2); for (int i = 0; i < n + m - 1; ++i) { c[i] = c2[i].x; } return c; } int main(){ cin.tie(nullptr); ios::sync_with_stdio(false); int n,m; cin >> n >> m; vector b(n); for (int i = 0; i < n; ++i) { cin >> b[i]; } vector a(n-1); int l = 0, r = 0; for (int i = 1; i < n; ++i) { a[i-1] = b[i] - b[i-1]; if (a[i-1] < 0) l += abs(a[i-1]); else r += a[i-1]; } vector dp(m+1); dp[0] = 1; for (int dif : a) { vector f(m+1); for (int i = abs(dif); i <= m; i += 2) { int j = (i-abs(dif))/2; f[i] = p.invp[j] * p.invp[abs(dif)+j]; } auto ndp = convolution(dp, f); swap(dp, ndp); while (dp.size() > m+1) dp.pop_back(); } modint res = 0; for (int i = 0; i <= m; ++i) { if (i > b[0]+b.back()) break; int al = b[0]+b.back()-i; if (al < 0) continue; int L = b[0]-al, R = b.back()-al; if (l > L or r > R) continue; res += dp[L+R] * p.invp[al] * p.invp[m-i]; } cout << res*p.p[m] << endl; }