#include using namespace std; using ll = long long; static const int MOD = 998244353; static const long long BRUTE_LIMIT = 2000000; 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; } }; long long comb_limited(int n, int r, long long limit) { if (r < 0 || r > n) return 0; r = min(r, n - r); long double val = 1.0; for (int i = 1; i <= r; i++) { val = val * (n - r + i) / i; if (val > limit) return limit + 1; } long long ans = 1; for (int i = 1; i <= r; i++) { ans = ans * (n - r + i) / i; if (ans > limit) return limit + 1; } return ans; } int brute_solve(int N, int M, int K) { vector> edges; for (int u = 0; u < N; u++) { for (int v = u + 1; v < N; v++) { edges.push_back({u, v}); } } int E = (int)edges.size(); vector removed(E, 0); for (int i = 0; i < M; i++) removed[i] = 1; sort(removed.begin(), removed.end()); int ans = 0; do { vector> g(N); for (int i = 0; i < E; i++) { if (removed[i]) continue; auto [u, v] = edges[i]; g[u].push_back(v); g[v].push_back(u); } vector dist(N, -1); queue q; dist[0] = 0; q.push(0); while (!q.empty()) { int v = q.front(); q.pop(); for (int to : g[v]) { if (dist[to] == -1) { dist[to] = dist[v] + 1; q.push(to); } } } if (dist[N - 1] == K) { ans++; if (ans >= MOD) ans -= MOD; } } while (next_permutation(removed.begin(), removed.end())); return ans; } // p(q) * (q^s - 1) // 多項式は常に長さ E+1 固定 vector mul_qs_minus_1_full(const vector &p, int s, int E) { vector res(E + 1, 0); // p(q) * q^s if (s <= E) { for (int i = 0; i + s <= E; i++) { res[i + s] = p[i]; } } // - p(q) for (int i = 0; i <= E; i++) { res[i] -= p[i]; if (res[i] < 0) res[i] += MOD; } return res; } // dst += scale * q^shift * src // 多項式は常に長さ E+1 固定 void add_shift_scaled_full(vector &dst, const vector &src, int shift, int scale, int E) { if (scale == 0 || shift > E) return; for (int i = 0; i + shift <= E; i++) { if (src[i] == 0) continue; dst[i + shift] = (dst[i + shift] + (ll)src[i] * scale) % MOD; } } int fast_solve(int N, int M, int K) { int E = N * (N - 1) / 2; int R = E - M; int S = N - 2; Comb comb; comb.init(E); // dp[r][s] is a polynomial in q of fixed length E+1. // r: number of ordinary vertices not reached yet // s: size of current BFS frontier vector>> dp( S + 1, vector>(S + 2, vector(E + 1, 0)) ); vector> active(S + 1, vector(S + 2, 0)); dp[S][1][0] = 1; active[S][1] = 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, vector(E + 1, 0)) ); vector> nactive(S + 1, vector(S + 2, 0)); for (int r = 0; r <= S; r++) { for (int s = 0; s <= S + 1; s++) { if (!active[r][s]) continue; vector cur = dp[r][s]; // cur * (q^s - 1)^t for (int t = 0; t <= r; t++) { int shift = t * (t - 1) / 2; int ways = comb.C(r, t); add_shift_scaled_full(ndp[r - t][t], cur, shift, ways, E); nactive[r - t][t] = 1; if (t != r) { cur = mul_qs_minus_1_full(cur, s, E); } } } } dp.swap(ndp); active.swap(nactive); } // H(q): generating polynomial for dist(1,N)=K in q=1+x. vector H(E + 1, 0); // N must have at least one edge to the current frontier: (q^s - 1). // All edges among the remaining r ordinary vertices, between them and N, // and between them and the current frontier are free. for (int r = 0; r <= S; r++) { for (int s = 0; s <= S + 1; s++) { if (!active[r][s]) continue; const vector &p = dp[r][s]; int base = s * r + r + r * (r - 1) / 2; // p(q) * (q^s - 1) * q^base for (int i = 0; i <= E; i++) { int val = p[i]; if (val == 0) continue; // + p(q) * q^{base+s} if (i + base + s <= E) { H[i + base + s] += val; if (H[i + base + s] >= MOD) H[i + base + s] -= MOD; } // - p(q) * q^base if (i + base <= E) { H[i + base] -= val; if (H[i + base] < 0) H[i + base] += MOD; } } } } ll ans = 0; for (int c = R; c <= E; c++) { ans += (ll)H[c] * comb.C(c, R) % MOD; ans %= MOD; } return (int)ans; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, M, K; cin >> N >> M >> K; int E = N * (N - 1) / 2; long long brute_count = comb_limited(E, M, BRUTE_LIMIT); if (brute_count <= BRUTE_LIMIT) { cout << brute_solve(N, M, K) << '\n'; } else { cout << fast_solve(N, M, K) << '\n'; } return 0; }