#include using namespace std; using ll = long long; static const int MOD = 998244353; ll modpow(ll a, ll e) { ll r = 1; while (e > 0) { if (e & 1) r = r * a % MOD; a = a * a % MOD; e >>= 1; } return r; } struct Comb { vector fact, ifact; void init(int n) { fact.assign(n + 1, 1); ifact.assign(n + 1, 1); for (int i = 1; i <= n; i++) fact[i] = (ll)fact[i - 1] * i % MOD; ifact[n] = (int)modpow(fact[n], MOD - 2); for (int i = n; i >= 1; i--) ifact[i - 1] = (ll)ifact[i] * i % MOD; } int C(int n, int r) const { if (r < 0 || r > n) return 0; return (ll)fact[n] * ifact[r] % MOD * ifact[n - r] % MOD; } }; static inline void trim(vector &a) { while (!a.empty() && a.back() == 0) a.pop_back(); } vector multiply_poly(const vector &a, const vector &b, int E) { if (a.empty() || b.empty()) return {}; int need = min(E + 1, (int)a.size() + (int)b.size() - 1); vector c(need, 0); for (int i = 0; i < (int)a.size(); i++) { if (a[i] == 0) continue; int lim = min((int)b.size() - 1, E - i); for (int j = 0; j <= lim; j++) { if (b[j] == 0) continue; c[i + j] = (c[i + j] + (ll)a[i] * b[j]) % MOD; } } trim(c); return c; } vector shift_poly(const vector &p, int shift, int E) { if (p.empty() || shift > E) return {}; int need = min(E + 1, shift + (int)p.size()); vector res(need, 0); for (int i = 0; i + shift <= E && i < (int)p.size(); i++) { res[i + shift] = p[i]; } trim(res); return res; } void add_scaled(vector &dst, const vector &src, int scale, int E) { if (src.empty() || scale == 0) return; if ((int)dst.size() < (int)src.size()) { dst.resize(src.size(), 0); } for (int i = 0; i < (int)src.size(); i++) { if (src[i] == 0) continue; dst[i] = (dst[i] + (ll)src[i] * scale) % MOD; } trim(dst); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, M, K; cin >> N >> M >> K; int E = N * (N - 1) / 2; int R = E - M; int S = N - 2; Comb comb; comb.init(E); // base_poly[s] = q^s - 1 vector> base_poly(S + 2); for (int s = 0; s <= S + 1; s++) { vector p(max(1, s + 1), 0); p[0] = MOD - 1; // -1 if (s <= E) { if ((int)p.size() <= s) p.resize(s + 1, 0); p[s] += 1; if (p[s] >= MOD) p[s] -= MOD; } trim(p); base_poly[s] = p; } // pow_poly[s][t] = (q^s - 1)^t vector>> pow_poly(S + 2, vector>(S + 1)); for (int s = 0; s <= S + 1; s++) { pow_poly[s][0] = vector{1}; for (int t = 1; t <= S; t++) { pow_poly[s][t] = multiply_poly(pow_poly[s][t - 1], base_poly[s], E); } } // kernel[s][t] = (q^s - 1)^t * q^{t(t-1)/2} vector>> kernel(S + 2, vector>(S + 1)); for (int s = 0; s <= S + 1; s++) { for (int t = 0; t <= S; t++) { int shift = t * (t - 1) / 2; kernel[s][t] = shift_poly(pow_poly[s][t], shift, E); } } // dp[r][s] is a polynomial in q. vector>> dp(S + 1, vector>(S + 2)); dp[S][1] = vector{1}; // Build layers 1,2,...,K-1 without reaching vertex N. for (int step = 0; step < K - 1; step++) { vector>> ndp(S + 1, vector>(S + 2)); for (int r = 0; r <= S; r++) { for (int s = 0; s <= S + 1; s++) { if (dp[r][s].empty()) continue; for (int t = 0; t <= r; t++) { int ways = comb.C(r, t); vector prod = multiply_poly(dp[r][s], kernel[s][t], E); add_scaled(ndp[r - t][t], prod, ways, E); } } } dp.swap(ndp); } // H(q): generating polynomial for dist(1,N)=K in q=1+x. vector H(E + 1, 0); for (int r = 0; r <= S; r++) { for (int s = 0; s <= S + 1; s++) { const vector &p = dp[r][s]; if (p.empty()) continue; int base = s * r + r + r * (r - 1) / 2; // final factor: (q^s - 1) q^base vector final_factor = shift_poly(base_poly[s], base, E); vector prod = multiply_poly(p, final_factor, E); add_scaled(H, prod, 1, E); } } // We need [x^R] H(1+x). If H(q)=sum_c h_c q^c, then // [x^R] H(1+x) = sum_c h_c * C(c,R). ll ans = 0; for (int c = R; c <= E; c++) { if (c < (int)H.size() && H[c] != 0) { ans += (ll)H[c] * comb.C(c, R) % MOD; ans %= MOD; } } cout << ans << '\n'; return 0; }