#include using namespace std; const long long MOD = 998244353; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N, M, K; if (!(cin >> N >> M >> K)) return 0; int total_edges = N * (N - 1) / 2; int rem_edges = total_edges - M; if (rem_edges < 0) { cout << 0 << '\n'; return 0; } int MAX_C = max(total_edges + 1, N + 1); vector> C(MAX_C, vector(MAX_C, 0)); for (int i = 0; i < MAX_C; i++) { C[i][0] = 1; for (int j = 1; j <= i; j++) { C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD; } } int UMAX = N; int SMAX = N; int EMAX = rem_edges; auto idx = [&](int prev_sz, int u, int e) { return (prev_sz * (UMAX + 1) + u) * (EMAX + 1) + e; }; int SZ = (SMAX + 1) * (UMAX + 1) * (EMAX + 1); vector curr(SZ, 0), nxt(SZ, 0); // 状態: dp[prev_sz][u][e] curr[idx(1, 0, 0)] = 1; for (int d = 1; d <= K; d++) { fill(nxt.begin(), nxt.end(), 0); for (int prev_sz = 0; prev_sz <= SMAX; prev_sz++) { for (int u = 0; u <= UMAX; u++) { for (int e = 0; e <= EMAX; e++) { long long ways = curr[idx(prev_sz, u, e)]; if (ways == 0) continue; int rem_v = (N - 2) - u; if (rem_v < 0) continue; int min_vars = 0; int max_vars = rem_v; if (d != K) { min_vars = max(min_vars, 1); } for (int k_vars = min_vars; k_vars <= max_vars; k_vars++) { int sz = k_vars + (d == K ? 1 : 0); if (sz == 0) continue; long long v_choices = C[rem_v][k_vars]; if (v_choices == 0) continue; // 直前の層 prev_sz との接続の組合せ // 各頂点1本以上 vector ways_to_connect(prev_sz + 1, 0); for (int j = 1; j <= prev_sz; j++) { ways_to_connect[j] = C[prev_sz][j]; } vector sz_conn(prev_sz * sz + 1, 0); sz_conn[0] = 1; for (int rep = 0; rep < sz; rep++) { vector next_sz_conn(sz_conn.size(), 0); for (int e1 = 0; e1 < (int)sz_conn.size(); e1++) { if (sz_conn[e1] == 0) continue; for (int e2 = 1; e2 <= prev_sz; e2++) { if (e1 + e2 < (int)next_sz_conn.size()) { next_sz_conn[e1 + e2] += sz_conn[e1] * ways_to_connect[e2]; next_sz_conn[e1 + e2] %= MOD; } } } sz_conn = next_sz_conn; } // 同一層内の辺 int inner_max = sz * (sz - 1) / 2; vector ways_inner(inner_max + 1, 0); for (int i = 0; i <= inner_max; i++) { ways_inner[i] = C[inner_max][i]; } long long base_ways = ways * v_choices % MOD; for (int e_conn = 0; e_conn < (int)sz_conn.size(); e_conn++) { long long w_conn = sz_conn[e_conn]; if (w_conn == 0) continue; for (int e_inner = 0; e_inner < (int)ways_inner.size(); e_inner++) { long long w_inner = ways_inner[e_inner]; int added_edges = e_conn + e_inner; if (e + added_edges > rem_edges) continue; int n_u = u + k_vars; int n_e = e + added_edges; long long n_ways = base_ways * w_conn % MOD; n_ways = n_ways * w_inner % MOD; int id = idx(sz, n_u, n_e); nxt[id] += n_ways; nxt[id] %= MOD; } } } } } } curr.swap(nxt); } long long ans = 0; for (int prev_sz = 0; prev_sz <= SMAX; prev_sz++) { for (int u = 0; u <= UMAX; u++) { for (int e = 0; e <= EMAX; e++) { long long ways = curr[idx(prev_sz, u, e)]; if (ways == 0) continue; int rem_v_final = (N - 2) - u; if (rem_v_final < 0) continue; int free_edges = rem_v_final * (rem_v_final - 1) / 2 + prev_sz * rem_v_final; int needed = rem_edges - e; if (0 <= needed && needed <= free_edges) { ans += ways * C[free_edges][needed] % MOD; ans %= MOD; } } } } cout << ans << '\n'; return 0; }