結果

問題 No.3589 Make Ends Meet (Hard)
コンテスト
ユーザー marc2825
提出日時 2026-06-09 13:07:20
言語 C++17
(gcc 15.2.0 + boost 1.90.0)
コンパイル:
g++-15 -O2 -lm -std=c++17 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
RE  
実行時間 -
コード長 3,733 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 1,316 ms
コンパイル使用メモリ 222,128 KB
実行使用メモリ 15,104 KB
最終ジャッジ日時 2026-07-10 21:00:27
合計ジャッジ時間 5,415 ms
ジャッジサーバーID
(参考情報)
judge3_0 / judge1_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample RE * 2 TLE * 1
other -- * 47
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

#include <bits/stdc++.h>
using namespace std;

using ll = long long;
const int MOD = 998244353;

using Poly = vector<int>;

Poly poly_mul(const Poly& a, const Poly& b, int E) {
    Poly res(E + 1, 0);

    for (int i = 0; i <= E; i++) {
        for (int j = 0; j + i <= E; j++) {
            res[i + j] = (res[i + j] + (ll)a[i] * b[j]) % MOD;
        }
    }

    return res;
}

void poly_add_scaled(Poly& dst, const Poly& src, int scale, int E) {
    for (int i = 0; i <= E; i++) {
        dst[i] = (dst[i] + (ll)src[i] * scale) % MOD;
    }
}

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;

    // binomial coefficients
    vector<vector<int>> C(E + 1, vector<int>(E + 1, 0));

    for (int i = 0; i <= E; i++) {
        C[i][0] = C[i][i] = 1;
        for (int j = 1; j < i; j++) {
            C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
            if (C[i][j] >= MOD) C[i][j] -= MOD;
        }
    }

    auto nCr = [&](int n, int r) -> int {
        if (r < 0 || r > n) return 0;
        return C[n][r];
    };

    // one_plus_pow[m] = (1+x)^m
    vector<Poly> one_plus_pow(E + 1, Poly(E + 1, 0));

    for (int m = 0; m <= E; m++) {
        for (int i = 0; i <= m; i++) {
            one_plus_pow[m][i] = C[m][i];
        }
    }

    // trans[b][c] =
    // ((1+x)^b - 1)^c * (1+x)^{c(c-1)/2}
    vector<vector<Poly>> trans(N + 1, vector<Poly>(N + 1, Poly(E + 1, 0)));

    for (int b = 0; b <= N; b++) {
        Poly base = one_plus_pow[b];
        base[0]--;
        if (base[0] < 0) base[0] += MOD;

        Poly power(E + 1, 0);
        power[0] = 1;

        for (int c = 0; c <= N; c++) {
            if (c > 0) {
                power = poly_mul(power, base, E);
            }

            int inside_edges = c * (c - 1) / 2;
            trans[b][c] = poly_mul(power, one_plus_pow[inside_edges], E);
        }
    }

    // dp[a][b]:
    // a = number of ordinary vertices used in L_1,...,L_j
    // b = size of current BFS layer L_j
    vector<vector<Poly>> dp(S + 1, vector<Poly>(N + 1, Poly(E + 1, 0)));

    // L_0 = {1}
    dp[0][1][0] = 1;

    for (int j = 0; j < K; j++) {
        vector<vector<Poly>> ndp(S + 1, vector<Poly>(N + 1, Poly(E + 1, 0)));

        bool last = (j + 1 == K);

        for (int a = 0; a <= S; a++) {
            int rem = S - a;

            for (int b = 0; b <= N; b++) {
                if (!last) {
                    // L_{j+1} contains only ordinary vertices.
                    for (int c = 1; c <= rem; c++) {
                        int ways = nCr(rem, c);
                        int a2 = a + c;

                        Poly tmp = poly_mul(dp[a][b], trans[b][c], E);
                        poly_add_scaled(ndp[a2][c], tmp, ways, E);
                    }
                } else {
                    // L_K must contain vertex N.
                    // If |L_K| = c, choose c-1 ordinary vertices.
                    for (int c = 1; c <= rem + 1; c++) {
                        int ways = nCr(rem, c - 1);
                        int a2 = a + c - 1;

                        Poly tmp = poly_mul(dp[a][b], trans[b][c], E);
                        poly_add_scaled(ndp[a2][c], tmp, ways, E);
                    }
                }
            }
        }

        dp.swap(ndp);
    }

    ll ans = 0;

    for (int a = 0; a <= S; a++) {
        int rem = S - a;

        for (int b = 0; b <= N; b++) {
            int free_edges = rem * b + rem * (rem - 1) / 2;

            Poly tmp = poly_mul(dp[a][b], one_plus_pow[free_edges], E);

            ans += tmp[R];
            ans %= MOD;
        }
    }

    cout << ans << '\n';
    return 0;
}
0