提出 #63635706


ソースコード 拡げる

#include <bits/stdc++.h>

#include <atcoder/dsu>

using namespace std;

vector<pair<int, int>> P_edge = {{0, 1}, {1, 2}, {2, 3}, {0, 3}, {3, 4}};
// Pを含むか判定する
// メモ化する
vector<int> memo_P(int(1 << 10), -1);
bool _is_P(vector<vector<bool>>& mat, vector<int> s) {  // 隣接行列 mat, 頂点集合 s
    int n = s.size();
    assert(n == 5);

    // メモ化するためにグラフにidxを振る
    int g_idx = 0;
    int pos = 0;
    for (int i = 0; i < 5; i++) {
        for (int j = i + 1; j < n; j++) {
            if (mat[s[i]][s[j]]) {
                g_idx |= 1 << pos;
            }
            pos++;
        }
    }

    if (memo_P[g_idx] != -1) return memo_P[g_idx];

    sort(s.begin(), s.end());
    do {  // P_edgeの辺がすべて存在すればOK
        bool ok = true;
        for (auto [u, v] : P_edge) {
            if (!mat[s[u]][s[v]]) ok = false;
        }
        if (ok) return memo_P[g_idx] = true;
    } while (next_permutation(s.begin(), s.end()));
    return memo_P[g_idx] = false;
}

vector<pair<int, int>> C_edge = {{0, 1}, {1, 2}, {2, 3}, {3, 4}};
// Pを含むか判定する
// メモ化する
vector<int> memo_C(int(1 << 10), -1);
bool _is_C(vector<vector<bool>>& mat, vector<int> s) {  // 隣接行列 mat, 頂点集合 s
    int n = s.size();
    assert(n == 5);

    // メモ化するためにグラフにidxを振る
    int g_idx = 0;
    int pos = 0;
    for (int i = 0; i < 5; i++) {
        for (int j = i + 1; j < n; j++) {
            if (mat[s[i]][s[j]]) {
                g_idx |= 1 << pos;
            }
            pos++;
        }
    }

    if (memo_C[g_idx] != -1) return memo_C[g_idx];

    sort(s.begin(), s.end());
    do {  // C_edgeの辺がすべて存在すればOK
        bool ok = true;
        for (auto [u, v] : C_edge) {
            if (!mat[s[u]][s[v]]) ok = false;
        }
        if (ok) return memo_C[g_idx] = true;
    } while (next_permutation(s.begin(), s.end()));
    return memo_C[g_idx] = false;
}

int longest_path(vector<vector<int>>& g) {
    int n = g.size();
    // bitDPでグラフの最長パスを求める
    vector<vector<int>> dp(1 << n, vector<int>(n, -100));
    for (int i = 0; i < n; i++) dp[1 << i][i] = 1;
    for (int i = 0; i < (1 << n); i++) {
        for (int j = 0; j < n; j++)
            if (dp[i][j] != -100) {
                for (int nj : g[j]) {
                    if (i & (1 << nj)) continue;
                    dp[i | (1 << nj)][nj] = max(dp[i | (1 << nj)][nj], dp[i][j] + 1);
                }
            }
    }
    int mx = 0;
    for (int i = 0; i < (1 << n); i++) {
        for (int j = 0; j < n; j++) mx = max(mx, dp[i][j]);
    }
    return mx;
}

// P を判定する
bool is_P(vector<vector<int>>& g) {
    int n = g.size();
    if (n < 5) return false;

    // 隣接行列を作る
    vector<vector<bool>> mat(n, vector<bool>(n, false));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < g[i].size(); j++) {
            mat[i][g[i][j]] = true;
        }
    }

    vector<int> perm(n, 0);
    for (int i = 0; i < 5; i++) perm[n - i - 1] = 1;
    do {  // すべての分け方について調べる
        vector<int> s;
        for (int i = 0; i < n; i++) {
            if (perm[i] == 1) s.push_back(i);
        }
        if (_is_P(mat, s)) return true;

    } while (next_permutation(perm.begin(), perm.end()));
    return false;
}

// P+P, P+C, C+C を判定する
// 0から順番に P+P, P+C, C+C, null
int is_P_pulus_P(vector<vector<int>>& g) {  // P+P, P+C, C+C
    int n = g.size();
    assert(n == 10);

    // 隣接行列を作る
    vector<vector<bool>> mat(n, vector<bool>(n, false));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < g[i].size(); j++) {
            mat[i][g[i][j]] = true;
        }
    }

    bool is_P_C = false;
    bool is_C_C = false;

    vector<int> perm(n, 0);
    for (int i = 5; i < n; i++) perm[i] = 1;
    do {  // すべての分け方について調べる
        vector<int> s1, s2;
        for (int i = 0; i < n; i++) {
            if (perm[i] == 0)
                s1.push_back(i);
            else
                s2.push_back(i);
        }
        bool is_P1 = _is_P(mat, s1);
        bool is_C1 = _is_C(mat, s1);
        bool is_P2 = _is_P(mat, s2);
        bool is_C2 = _is_C(mat, s2);
        if (is_P1 && is_P2) return 0;
        if ((is_P1 && is_C2) || (is_C1 && is_P2)) is_P_C = true;
        if (is_C1 && is_C2) is_C_C = true;

    } while (next_permutation(perm.begin(), perm.end()));
    if (is_P_C) return 1;
    if (is_C_C) return 2;
    return 3;
}

// 連結成分を分類する
// 0から順番に P+P, P+C, C+C/N/P, C+C/N, C+C, P/N, P/U, N, U, P, C, null
int classification(vector<vector<int>>& g) {
    int n = g.size();
    if (n == 10) {
        int res = is_P_pulus_P(g);
        if (res == 0) return 0;  // P+P
        if (res == 1) return 1;  // P+C
        if (res == 2) {
            if (is_P(g)) return 2;  // C+C/N/P
            int dist = longest_path(g);
            if (dist >= 7)
                return 3;  // C+C/N
            else
                return 4;  // C+C
        }
    }
    if (is_P(g)) {
        int dist = longest_path(g);
        if (dist >= 7)
            return 5;  // P/N
        else if (dist >= 6)
            return 6;  // P/U
        else
            return 9;  // P
    } else {
        int dist = longest_path(g);
        if (dist >= 7)
            return 7;  // N
        else if (dist >= 6)
            return 8;  // U
        else if (dist >= 5)
            return 10;  // C
        else
            return 11;  // null
    }
}

int main() {
    // 入力
    int n, m;
    cin >> n >> m;
    atcoder::dsu uf(n);
    vector<pair<int, int>> edge(m);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        edge[i] = {u, v};
        uf.merge(u, v);
    }

    vector<pair<int, int>> idx(n);  // 頂点がどのグループの何番目の要素か
    vector<vector<int>> group = uf.groups();
    for (int i = 0; i < group.size(); i++) {
        assert(group[i].size() <= 10);  // 連結成分数は10以下
        for (int j = 0; j < group[i].size(); j++) {
            idx[group[i][j]] = {i, j};
        }
    }

    vector<vector<vector<int>>> g(group.size());  // 各連結成分についてグラフをつくる
    for (int i = 0; i < group.size(); i++) {
        g[i].assign(group[i].size(), vector<int>());
    }
    for (auto [u, v] : edge) {
        assert(idx[u].first == idx[v].first);
        int i = idx[u].second;
        int j = idx[v].second;
        g[idx[u].first][i].push_back(j);
        g[idx[u].first][j].push_back(i);
    }

    // P+P, P+C, C+C/N/P, C+C/N, C+C, P/N, P/U, N, U, P, C, null
    vector<int> cnt(12, 0);

    for (int i = 0; i < group.size(); i++) {
        cnt[classification(g[i])]++;
    }

    // 二分探索
    int ok = 0, ng = n;
    while (ng - ok > 1) {
        int mid = (ok + ng) / 2;
        bool fn = false;
        // P+P, P+C を分解する数を全探索
        for (int i = 0; i <= cnt[0] + cnt[1]; i++) {
            // P+P, P+C, C+C/N/P, C+C/N, C+C, P/N, P/U, N, U, P, C, null
            vector<int> cur = cnt;

            // 分解する順番は P+P -> P+C でよい
            int cut_0 = min(cnt[0], i);
            int cut_1 = i - cut_0;

            cur[0] -= cut_0;
            cur[9] += cut_0 * 2;

            cur[1] -= cut_1;
            cur[9] += cut_1;
            cur[10] += cut_1;

            // Pを詰め込む
            int P = mid;

            vector<int> P_order = {9, 6, 5, 2};

            int dec = 0;

            for (int i : P_order) {
                dec = min(cur[i], P);
                P -= dec;
                cur[i] -= dec;
                if (i == 1) cur[10] += dec;  // Cを増やす
            }

            // Nを詰め込む
            int N = mid;

            vector<int> N_order = {7, 5, 3, 2, 1, 0};

            for (int i : N_order) {
                dec = min(cur[i], N);
                N -= dec;
                cur[i] -= dec;
            }

            // Uを詰め込む
            int U = mid;

            vector<int> U_order = {8, 6, 7, 5, 4, 3, 2, 1, 0};

            for (int i : U_order) {
                dec = min(cur[i], U);
                U -= dec;
                cur[i] -= dec;
            }

            // Cを詰め込む
            int C = mid;

            vector<int> C_order = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

            for (int i : C_order) {
                if (i <= 4) {
                    dec = min(cur[i] * 2, C);
                } else {
                    dec = min(cur[i], C);
                }
                C -= dec;
            }

            if (N == 0 && U == 0 && P == 0 && C == 0) {
                fn = true;
                break;
            }
        }
        if (fn)
            ok = mid;
        else
            ng = mid;
    }
    cout << ok << endl;
}

提出情報

提出日時
問題 M - NUPaCking
ユーザ Jinapetto
言語 C++ 20 (gcc 12.2)
得点 100
コード長 9280 Byte
結果 AC
実行時間 1822 ms
メモリ 14380 KiB

コンパイルエラー

Main.cpp: In function ‘bool _is_P(std::vector<std::vector<bool> >&, std::vector<int>)’:
Main.cpp:35:38: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
   35 |         if (ok) return memo_P[g_idx] = true;
Main.cpp:37:26: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
   37 |     return memo_P[g_idx] = false;
Main.cpp: In function ‘bool _is_C(std::vector<std::vector<bool> >&, std::vector<int>)’:
Main.cpp:68:38: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
   68 |         if (ok) return memo_C[g_idx] = true;
Main.cpp:70:26: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
   70 |     return memo_C[g_idx] = false;
Main.cpp: In function ‘bool is_P(std::vector<std::vector<int> >&)’:
Main.cpp:102:27: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<int>::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
  102 |         for (int j = 0; j < g[i].size(); j++) {
      |                         ~~^~~~~~~~~~~~~
Main.cpp: In function ‘int is_P_pulus_P(std::vector<std::vector<int> >&)’:
Main.cpp:129:27: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<int>::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
  129 |         for (int j = 0; j < g[i].size(); j++) {
      |                         ~~^~~~~~~~~~~~~
Main.cpp: In function ‘int main()’:
Main.cpp:215:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<std::vector<int> >::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
  215 |     for (int i = 0; i < group.size(); i++) {
      |                     ~~^~~~~~~~~~~~~~
Main.cpp:217:27: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<int>::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
  217 |         for (int j = 0; j < group[i].size(); j++) {
      |                         ~~^~~~~~~~~~~~~~~~~
Main.cpp:223:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<std::vector<int> >::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
  223 |     for (int i = 0; i < group.size(); i++) {
      |                     ~~^~~~~~~~~~~~~~
Main.cpp:237:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<std::vector<int> >::size_type’ {aka ‘long unsigned int’} [-Wsign-compare]
  237 |     for (int i = 0; i < group.size(); i++) {
      |                     ~~^~~~~~~~~~~~~~

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 100 / 100
結果
AC × 3
AC × 86
セット名 テストケース
Sample 01_sample_01, 02_sample_02, 03_sample_03
All 01_sample_01, 02_sample_02, 03_sample_03, fix_01, fix_02, fix_03, fix_04, fix_05, fix_06, fix_07, fix_08, fix_09, fix_10, fix_11, fix_12, fix_13, fix_14, fix_15, fix_16, fix_17, fix_18, fix_19, fix_20, fix_21, fix_22, fix_23, fix_24, fix_25, fix_26, fix_27, fix_28, fix_29, fix_30, fix_31, fix_32, fix_33, fix_34, fix_35, fix_36, fix_37, fix_38, fix_39, fix_40, fix_41, fix_42, fix_43, fix_44, fix_45, fix_46, fix_47, fix_48, fix_49, fix_50, fix_51, fix_52, fix_53, fix_54, fix_55, fix_56, fix_57, fix_58, fix_59, fix_60, fix_61, fix_62, fix_63, fix_64, fix_65, fix_66, fix_67, fix_68, fix_69, fix_70, fix_71, fix_72, random_maxN_01, random_maxN_02, random_maxN_03, random_maxN_04, random_maxN_05, random_maxN_06, random_maxN_07, random_maxN_08, random_maxN_09, random_maxN_10, uni_01
ケース名 結果 実行時間 メモリ
01_sample_01 AC 4 ms 3456 KiB
02_sample_02 AC 1 ms 3416 KiB
03_sample_03 AC 3 ms 3516 KiB
fix_01 AC 7 ms 3708 KiB
fix_02 AC 3 ms 3548 KiB
fix_03 AC 2 ms 3672 KiB
fix_04 AC 3 ms 3604 KiB
fix_05 AC 3 ms 3536 KiB
fix_06 AC 3 ms 3548 KiB
fix_07 AC 2 ms 3592 KiB
fix_08 AC 3 ms 3736 KiB
fix_09 AC 3 ms 3552 KiB
fix_10 AC 2 ms 3496 KiB
fix_11 AC 3 ms 3488 KiB
fix_12 AC 2 ms 3604 KiB
fix_13 AC 2 ms 3496 KiB
fix_14 AC 4 ms 3736 KiB
fix_15 AC 3 ms 3548 KiB
fix_16 AC 3 ms 3536 KiB
fix_17 AC 3 ms 3580 KiB
fix_18 AC 2 ms 3512 KiB
fix_19 AC 2 ms 3524 KiB
fix_20 AC 5 ms 3528 KiB
fix_21 AC 2 ms 3636 KiB
fix_22 AC 2 ms 3540 KiB
fix_23 AC 2 ms 3664 KiB
fix_24 AC 3 ms 3500 KiB
fix_25 AC 2 ms 3524 KiB
fix_26 AC 3 ms 3536 KiB
fix_27 AC 2 ms 3488 KiB
fix_28 AC 2 ms 3540 KiB
fix_29 AC 3 ms 3560 KiB
fix_30 AC 3 ms 3560 KiB
fix_31 AC 3 ms 3668 KiB
fix_32 AC 4 ms 3568 KiB
fix_33 AC 4 ms 3500 KiB
fix_34 AC 5 ms 3556 KiB
fix_35 AC 5 ms 3556 KiB
fix_36 AC 3 ms 3556 KiB
fix_37 AC 4 ms 3592 KiB
fix_38 AC 4 ms 3564 KiB
fix_39 AC 4 ms 3676 KiB
fix_40 AC 4 ms 3564 KiB
fix_41 AC 5 ms 3760 KiB
fix_42 AC 416 ms 8488 KiB
fix_43 AC 2 ms 3628 KiB
fix_44 AC 205 ms 8708 KiB
fix_45 AC 302 ms 8596 KiB
fix_46 AC 372 ms 6628 KiB
fix_47 AC 48 ms 4916 KiB
fix_48 AC 404 ms 6848 KiB
fix_49 AC 236 ms 9304 KiB
fix_50 AC 410 ms 8624 KiB
fix_51 AC 312 ms 7312 KiB
fix_52 AC 604 ms 9484 KiB
fix_53 AC 331 ms 6792 KiB
fix_54 AC 330 ms 6948 KiB
fix_55 AC 533 ms 9176 KiB
fix_56 AC 458 ms 8128 KiB
fix_57 AC 412 ms 8068 KiB
fix_58 AC 509 ms 9580 KiB
fix_59 AC 327 ms 8224 KiB
fix_60 AC 285 ms 7536 KiB
fix_61 AC 602 ms 11496 KiB
fix_62 AC 567 ms 10992 KiB
fix_63 AC 490 ms 8652 KiB
fix_64 AC 456 ms 9188 KiB
fix_65 AC 422 ms 8000 KiB
fix_66 AC 731 ms 11852 KiB
fix_67 AC 636 ms 10644 KiB
fix_68 AC 675 ms 10088 KiB
fix_69 AC 634 ms 10960 KiB
fix_70 AC 381 ms 9496 KiB
fix_71 AC 210 ms 6492 KiB
fix_72 AC 193 ms 5956 KiB
random_maxN_01 AC 1822 ms 13772 KiB
random_maxN_02 AC 1787 ms 13840 KiB
random_maxN_03 AC 1809 ms 13844 KiB
random_maxN_04 AC 1813 ms 13832 KiB
random_maxN_05 AC 1790 ms 13932 KiB
random_maxN_06 AC 1802 ms 13932 KiB
random_maxN_07 AC 1810 ms 13852 KiB
random_maxN_08 AC 1790 ms 13828 KiB
random_maxN_09 AC 1793 ms 13792 KiB
random_maxN_10 AC 1794 ms 14004 KiB
uni_01 AC 1674 ms 14380 KiB