結果

問題 No.3769 Even Contraction
コンテスト
ユーザー marc2825
提出日時 2026-10-04 20:30:14
言語 C++17
(gcc 15.3.0 + boost 1.92.0 + ACL)
コンパイル:
g++-15 -O2 -lm -std=c++17 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
WA  
実行時間 -
コード長 27,274 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,141 ms
コンパイル使用メモリ 286,672 KB
実行使用メモリ 22,528 KB
最終ジャッジ日時 2026-10-16 20:56:24
合計ジャッジ時間 8,594 ms
ジャッジサーバーID
(参考情報)
judge5_0 / judge1_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 31 WA * 16
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

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

const int NEG = -1e9;

struct Input {
    int n;
    vector<vector<int>> g;
    vector<int> a;
};

Input read_input() {
    Input in;
    cin >> in.n;
    in.g.assign(in.n, {});
    for (int i = 0; i < in.n - 1; i++) {
        int u, v;
        cin >> u >> v;
        --u, --v;
        in.g[u].push_back(v);
        in.g[v].push_back(u);
    }
    in.a.resize(in.n);
    for (int& x : in.a) cin >> x;
    return in;
}

struct DSU {
    vector<int> p, sz;

    DSU(int n = 0) : p(n, -1), sz(n, 1) {}

    int root(int x) {
        return p[x] < 0 ? x : p[x] = root(p[x]);
    }

    bool unite(int a, int b) {
        a = root(a);
        b = root(b);
        if (a == b) return false;
        if (sz[a] < sz[b]) swap(a, b);
        p[b] = a;
        sz[a] += sz[b];
        return true;
    }
};

bool legal(int x, int y) {
    return (x & 1) == (y & 1);
}

bool is02(int x, int y) {
    return (x == 0 && y == 2) || (x == 2 && y == 0);
}

// ============================================================
// 動的に木を縮約するための雑なヘルパー
// ============================================================

struct DynTree {
    int n;
    vector<unordered_set<int>> adj;
    vector<int> val;
    vector<char> alive;

    DynTree(const Input& in)
        : n(in.n), adj(n), val(in.a), alive(n, 1) {
        for (int v = 0; v < n; v++) {
            for (int u : in.g[v]) adj[v].insert(u);
        }
    }

    bool connected(int u, int v) const {
        return 0 <= u && u < n &&
               0 <= v && v < n &&
               alive[u] && alive[v] &&
               adj[u].count(v);
    }

    int merge_edge(int u, int v) {
        int nv = (val[u] + val[v]) / 2;

        adj[u].erase(v);
        adj[v].erase(u);

        // small-to-large
        if (adj[u].size() < adj[v].size()) swap(u, v);

        vector<int> mv(adj[v].begin(), adj[v].end());

        for (int w : mv) {
            adj[w].erase(v);
            adj[w].insert(u);
            adj[u].insert(w);
        }

        adj[v].clear();
        alive[v] = false;
        val[u] = nv;

        return u;
    }
};

int run_phase(
    DynTree& d,
    function<bool(int, int)> ok
) {
    queue<pair<int, int>> q;

    for (int u = 0; u < d.n; u++) {
        if (!d.alive[u]) continue;
        for (int v : d.adj[u]) {
            if (u < v) q.push({u, v});
        }
    }

    int got = 0;

    while (!q.empty()) {
        auto [u, v] = q.front();
        q.pop();

        if (!d.connected(u, v)) continue;
        if (!ok(d.val[u], d.val[v])) continue;

        int w = d.merge_edge(u, v);
        got++;

        for (int z : d.adj[w]) {
            q.push({w, z});
        }
    }

    return got;
}

// ============================================================
// 1.
// 「同じ値の辺は全部先に縮約して損しない」
// → その後は適当に合法辺を縮約
//
// 0-2-2-0 などで死亡
// ============================================================

int wrong1(const Input& in) {
    DynTree d(in);
    int ans = 0;

    ans += run_phase(
        d,
        [](int x, int y) {
            return x == y;
        }
    );

    ans += run_phase(
        d,
        [](int x, int y) {
            return legal(x, y);
        }
    );

    return ans;
}

// ============================================================
// 2.
// 完全にフェーズ固定
//
// 同値縮約
// → 0-2
// → 1-1
//
// という順番だけで処理
// ============================================================

int wrong2(const Input& in) {
    DynTree d(in);
    int ans = 0;

    ans += run_phase(
        d,
        [](int x, int y) {
            return x == y;
        }
    );

    ans += run_phase(
        d,
        [](int x, int y) {
            return is02(x, y);
        }
    );

    ans += run_phase(
        d,
        [](int x, int y) {
            return x == 1 && y == 1;
        }
    );

    return ans;
}

// ============================================================
// 3.
// 「木なら葉から貪欲でよい」
//
// 縮約可能な葉辺だけをどんどん縮約する。
// 1-0-2-0 などで死亡。
// ============================================================

int wrong3(const Input& in) {
    DynTree d(in);
    int ans = 0;

    queue<int> q;

    for (int v = 0; v < d.n; v++) {
        if (d.adj[v].size() == 1) q.push(v);
    }

    while (!q.empty()) {
        int v = q.front();
        q.pop();

        if (!d.alive[v]) continue;
        if (d.adj[v].size() != 1) continue;

        int u = *d.adj[v].begin();

        if (!legal(d.val[v], d.val[u])) continue;

        int w = d.merge_edge(v, u);
        ans++;

        if (d.adj[w].size() == 1) {
            q.push(w);
        }

        for (int z : d.adj[w]) {
            if (d.adj[z].size() == 1) {
                q.push(z);
            }
        }
    }

    return ans;
}

// ============================================================
// 4.
// 「0-2 -> 1 が特殊だから、とにかく 0-2 を優先」
//
// 0-2 が存在する限り最優先。
// なければ他の合法辺。
// ============================================================

int wrong4(const Input& in) {
    DynTree d(in);
    int ans = 0;

    queue<pair<int, int>> q02;
    queue<pair<int, int>> qo;

    auto push_edge = [&](int u, int v) {
        if (!d.connected(u, v)) return;

        int x = d.val[u];
        int y = d.val[v];

        if (!legal(x, y)) return;

        if (is02(x, y)) {
            q02.push({u, v});
        } else {
            qo.push({u, v});
        }
    };

    for (int u = 0; u < d.n; u++) {
        for (int v : d.adj[u]) {
            if (u < v) push_edge(u, v);
        }
    }

    while (true) {
        pair<int, int> e = {-1, -1};

        while (!q02.empty()) {
            auto [u, v] = q02.front();
            q02.pop();

            if (
                d.connected(u, v) &&
                is02(d.val[u], d.val[v])
            ) {
                e = {u, v};
                break;
            }
        }

        if (e.first == -1) {
            while (!qo.empty()) {
                auto [u, v] = qo.front();
                qo.pop();

                if (
                    d.connected(u, v) &&
                    legal(d.val[u], d.val[v]) &&
                    !is02(d.val[u], d.val[v])
                ) {
                    e = {u, v};
                    break;
                }
            }
        }

        if (e.first == -1) break;

        int w = d.merge_edge(e.first, e.second);
        ans++;

        for (int z : d.adj[w]) {
            push_edge(w, z);
        }
    }

    return ans;
}

// ============================================================
// 0-2 辺だけからなる maximum matching
// ============================================================

int matching02(const Input& in) {
    int n = in.n;

    // dp[v][0]:
    // v は親とはマッチしていない
    //
    // dp[v][1]:
    // v は親とマッチ済み
    vector<array<int, 2>> dp(n);

    function<void(int, int)> dfs =
        [&](int v, int p) {

            int base = 0;

            for (int u : in.g[v]) {
                if (u == p) continue;

                dfs(u, v);
                base += dp[u][0];
            }

            dp[v][1] = base;
            dp[v][0] = base;

            for (int u : in.g[v]) {
                if (u == p) continue;
                if (!is02(in.a[v], in.a[u])) continue;

                dp[v][0] = max(
                    dp[v][0],
                    base
                    - dp[u][0]
                    + dp[u][1]
                    + 1
                );
            }
        };

    dfs(0, -1);

    return dp[0][0];
}

// ============================================================
// 5.
// 「同値辺は取る +
//   0-2 辺は maximum matching」
//
// 1-0-2 など、生成した1の価値を評価できず死亡。
// ============================================================

int wrong5(const Input& in) {
    int same = 0;

    for (int v = 0; v < in.n; v++) {
        for (int u : in.g[v]) {
            if (v < u && in.a[v] == in.a[u]) {
                same++;
            }
        }
    }

    return min(
        in.n - 1,
        same + matching02(in)
    );
}

// ============================================================
// 6.
// 「0/2 の連結成分に 0 と 2 が両方存在すれば、
//   その成分全体を1にできる」
//
// 星型などで死亡。
// ============================================================

int wrong6(const Input& in) {
    int n = in.n;

    DSU uf(n);

    // 1 を除いた 0/2 成分
    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (v >= u) continue;

            if (
                in.a[v] != 1 &&
                in.a[u] != 1
            ) {
                uf.unite(v, u);
            }
        }
    }

    vector<int> sz(n);
    vector<int> has0(n);
    vector<int> has2(n);

    for (int v = 0; v < n; v++) {
        if (in.a[v] == 1) continue;

        int r = uf.root(v);

        sz[r]++;
        has0[r] |= (in.a[v] == 0);
        has2[r] |= (in.a[v] == 2);
    }

    int ans = 0;

    // 0/2成分内部は全部縮約可能だと決めつける
    for (int r = 0; r < n; r++) {
        if (sz[r]) {
            ans += sz[r] - 1;
        }
    }

    // mixed な成分は「1になれる」とみなす
    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (v >= u) continue;

            if (in.a[v] == 1 && in.a[u] == 1) {
                ans++;
            }

            else if (
                in.a[v] == 1 &&
                in.a[u] != 1
            ) {
                int r = uf.root(u);

                if (has0[r] && has2[r]) {
                    ans++;
                }
            }

            else if (
                in.a[u] == 1 &&
                in.a[v] != 1
            ) {
                int r = uf.root(v);

                if (has0[r] && has2[r]) {
                    ans++;
                }
            }
        }
    }

    return min(n - 1, ans);
}

// ============================================================
// 同値連結成分を縮約
// ============================================================

struct CompTree {
    int m;
    int internal;

    vector<vector<int>> g;
    vector<int> val;
    vector<int> sz;
};

CompTree compress_equal(const Input& in) {
    int n = in.n;

    DSU uf(n);

    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (
                v < u &&
                in.a[v] == in.a[u]
            ) {
                uf.unite(v, u);
            }
        }
    }

    vector<int> id(n, -1);

    int m = 0;

    for (int v = 0; v < n; v++) {
        if (uf.root(v) == v) {
            id[v] = m++;
        }
    }

    vector<int> rid(n);

    for (int v = 0; v < n; v++) {
        rid[v] = id[uf.root(v)];
    }

    CompTree ct;

    ct.m = m;
    ct.internal = n - m;

    ct.g.assign(m, {});
    ct.val.assign(m, 0);
    ct.sz.assign(m, 0);

    for (int v = 0; v < n; v++) {
        int c = rid[v];

        ct.val[c] = in.a[v];
        ct.sz[c]++;
    }

    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (v >= u) continue;
            if (rid[v] == rid[u]) continue;

            ct.g[rid[v]].push_back(rid[u]);
            ct.g[rid[u]].push_back(rid[v]);
        }
    }

    return ct;
}

// ============================================================
// 7.
// 「同値成分を1頂点に完全縮約してから
//   4状態DPすればよい」
//
// port情報を失う。
// 0-0 の異なる頂点に 2 が付く場合などを区別できない。
// ============================================================

int wrong7(const Input& in) {
    auto ct = compress_equal(in);

    int m = ct.m;

    vector<array<int, 4>> dp(m);

    function<void(int, int)> dfs =
        [&](int v, int p) {

            // 0: 非1
            // 1: 将来1
            // 2: 1かつ余裕あり
            // 3: 1かつ余裕なし

            array<int, 4> cur = {
                NEG, NEG, NEG, NEG
            };

            if (ct.val[v] == 1) {
                cur[2] = 0;
            } else {
                cur[0] = 0;
                cur[1] = 0;
            }

            for (int u : ct.g[v]) {
                if (u == p) continue;

                dfs(u, v);

                array<int, 4> nxt = {
                    NEG, NEG, NEG, NEG
                };

                for (int k = 0; k < 4; k++) {
                    if (cur[k] <= NEG / 2) continue;

                    for (int j = 0; j < 4; j++) {
                        if (dp[u][j] <= NEG / 2) continue;

                        // 辺を使わない
                        // 子の予約状態はここでは残せない
                        if (j != 1) {
                            nxt[k] = max(
                                nxt[k],
                                cur[k] + dp[u][j]
                            );
                        }

                        // 両方1なら 1-1 として縮約
                        if (
                            k != 0 &&
                            j != 0 &&
                            k != 1 &&
                            j != 1
                        ) {
                            nxt[k] = max(
                                nxt[k],
                                cur[k] + dp[u][j] + 1
                            );
                        }

                        // 0-2 を起爆として使用
                        if (
                            is02(ct.val[v], ct.val[u]) &&
                            k != 0 &&
                            j != 0 &&
                            k != 3 &&
                            j != 3
                        ) {
                            nxt[3] = max(
                                nxt[3],
                                cur[k] + dp[u][j] + 1
                            );
                        }
                    }
                }

                cur = nxt;
            }

            dp[v] = cur;
        };

    dfs(0, -1);

    int best = max({
        dp[0][0],
        dp[0][2],
        dp[0][3]
    });

    return ct.internal + best;
}

// ============================================================
// 8.
// dp[v][0/1/2]
//
// 「部分木を完全に処理した後の
//   vを含む塊の最終値だけ持てばよい」
//
// 0-0-2 などで予約ができず死亡。
// ============================================================

int wrong8(const Input& in) {
    int n = in.n;

    vector<array<int, 3>> dp(n);

    function<void(int, int)> dfs =
        [&](int v, int p) {

            array<int, 3> cur = {
                NEG, NEG, NEG
            };

            cur[in.a[v]] = 0;

            for (int u : in.g[v]) {
                if (u == p) continue;

                dfs(u, v);

                array<int, 3> nxt = {
                    NEG, NEG, NEG
                };

                for (int x = 0; x < 3; x++) {
                    if (cur[x] <= NEG / 2) continue;

                    for (int y = 0; y < 3; y++) {
                        if (dp[u][y] <= NEG / 2) continue;

                        // 親子辺を残す
                        nxt[x] = max(
                            nxt[x],
                            cur[x] + dp[u][y]
                        );

                        // 今ここで縮約
                        if ((x & 1) == (y & 1)) {
                            int z = (x + y) / 2;

                            nxt[z] = max(
                                nxt[z],
                                cur[x] + dp[u][y] + 1
                            );
                        }
                    }
                }

                cur = nxt;
            }

            dp[v] = cur;
        };

    dfs(0, -1);

    return max({
        dp[0][0],
        dp[0][1],
        dp[0][2]
    });
}

// ============================================================
// 9.
// さらに状態を潰して
//
// 0: 元の非1色のまま
// 1: 1になれる
//
// だけでDP。
// 「余裕あり1 / 余裕なし1 / 予約」を区別しない。
// ============================================================

int wrong9(const Input& in) {
    int n = in.n;

    vector<array<int, 2>> dp(n);

    function<void(int, int)> dfs =
        [&](int v, int p) {

            array<int, 2> cur = {
                NEG, NEG
            };

            if (in.a[v] == 1) {
                cur[1] = 0;
            } else {
                cur[0] = 0;
            }

            for (int u : in.g[v]) {
                if (u == p) continue;

                dfs(u, v);

                array<int, 2> nxt = {
                    NEG, NEG
                };

                for (int s = 0; s < 2; s++) {
                    if (cur[s] <= NEG / 2) continue;

                    for (int t = 0; t < 2; t++) {
                        if (dp[u][t] <= NEG / 2) continue;

                        int x = s ? 1 : in.a[v];
                        int y = t ? 1 : in.a[u];

                        // 辺を使わない
                        nxt[s] = max(
                            nxt[s],
                            cur[s] + dp[u][t]
                        );

                        if ((x & 1) == (y & 1)) {
                            int z = (x + y) / 2;

                            int ns = (z == 1);

                            if (
                                z == 1 ||
                                z == in.a[v]
                            ) {
                                nxt[ns] = max(
                                    nxt[ns],
                                    cur[s] + dp[u][t] + 1
                                );
                            }
                        }
                    }
                }

                cur = nxt;
            }

            dp[v] = cur;
        };

    dfs(0, -1);

    return max(
        dp[0][0],
        dp[0][1]
    );
}

// ============================================================
// 10.
// 「初期値1で木を分割し、
//   各 0/2 成分を独立最適化」
//
// mixed成分なら隣接する1全部につながる、と考える。
// ============================================================

int wrong10(const Input& in) {
    int n = in.n;

    DSU uf(n);

    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (v >= u) continue;

            if (
                in.a[v] != 1 &&
                in.a[u] != 1
            ) {
                uf.unite(v, u);
            }
        }
    }

    vector<int> has0(n);
    vector<int> has2(n);

    for (int v = 0; v < n; v++) {
        if (in.a[v] == 1) continue;

        int r = uf.root(v);

        has0[r] |= (in.a[v] == 0);
        has2[r] |= (in.a[v] == 2);
    }

    int ans = matching02(in);

    // 同値辺は全部安全だと仮定
    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (
                v < u &&
                in.a[v] == in.a[u]
            ) {
                ans++;
            }
        }
    }

    // mixed component は隣の1全部と接続可能と仮定
    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (v >= u) continue;

            if (
                in.a[v] == 1 &&
                in.a[u] != 1
            ) {
                int r = uf.root(u);

                if (has0[r] && has2[r]) {
                    ans++;
                }
            }

            if (
                in.a[u] == 1 &&
                in.a[v] != 1
            ) {
                int r = uf.root(v);

                if (has0[r] && has2[r]) {
                    ans++;
                }
            }
        }
    }

    return min(n - 1, ans);
}

// ============================================================
// 11.
// 木構造を無視。
// #0, #1, #2 だけで答えを計算。
// ============================================================

int wrong11(const Input& in) {
    int c[3] = {};

    for (int x : in.a) {
        c[x]++;
    }

    int k = min(c[0], c[2]);

    // 0+2 を k 回
    int ans = k;

    // 作った1と元の1を全部連結できると仮定
    int ones = c[1] + k;

    if (ones) {
        ans += ones - 1;
    }

    // 残った0同士・2同士も全部連結できると仮定
    int r0 = c[0] - k;
    int r2 = c[2] - k;

    if (r0) ans += r0 - 1;
    if (r2) ans += r2 - 1;

    return min(in.n - 1, ans);
}

// ============================================================
// 12.
// 0/2領域について
//
// 「0の同値成分数」と
// 「2の同値成分数」の差
//
// だけで残る個数が決まる、と仮定。
// ============================================================

int wrong12(const Input& in) {
    int n = in.n;

    DSU mono(n);
    DSU region(n);

    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (v >= u) continue;

            if (
                in.a[v] != 1 &&
                in.a[u] != 1
            ) {
                region.unite(v, u);
            }

            if (
                in.a[v] != 1 &&
                in.a[v] == in.a[u]
            ) {
                mono.unite(v, u);
            }
        }
    }

    unordered_map<int, vector<int>> verts;

    for (int v = 0; v < n; v++) {
        if (in.a[v] != 1) {
            verts[region.root(v)].push_back(v);
        }
    }

    int ans = 0;

    for (auto& [r, vs] : verts) {
        set<int> zero_comp;
        set<int> two_comp;

        for (int v : vs) {
            if (in.a[v] == 0) {
                zero_comp.insert(mono.root(v));
            } else {
                two_comp.insert(mono.root(v));
            }
        }

        int c0 = zero_comp.size();
        int c2 = two_comp.size();

        // 差だけ残る、と仮定
        int rem = max(
            1,
            abs(c0 - c2)
        );

        ans += (int)vs.size() - rem;
    }

    // 1-1 は普通に全部取る
    for (int v = 0; v < n; v++) {
        for (int u : in.g[v]) {
            if (
                v < u &&
                in.a[v] == 1 &&
                in.a[u] == 1
            ) {
                ans++;
            }
        }
    }

    return min(n - 1, ans);
}

// ============================================================
// 13.
// 「0/2 頂点を全部覆う perfect matching があれば
//   全部縮約可能」
//
// なければ matching 中心で数える。
// ============================================================

int wrong13(const Input& in) {
    int non1 = 0;
    int c1 = 0;

    for (int x : in.a) {
        non1 += (x != 1);
        c1 += (x == 1);
    }

    int m = matching02(in);

    if (2 * m == non1) {
        return in.n - 1;
    }

    int same = 0;

    for (int v = 0; v < in.n; v++) {
        for (int u : in.g[v]) {
            if (
                v < u &&
                in.a[v] == in.a[u]
            ) {
                same++;
            }
        }
    }

    int ans = same + m;

    // matching で作った1と元の1を全部合体できると仮定
    if (c1 + m > 0) {
        ans += max(
            0,
            c1 + m - 1
        );
    }

    return min(in.n - 1, ans);
}

// ============================================================
// component tree 上での b-matching
//
// 「同値成分は capacity 個まで
//   0-2 境界辺を使える」
//
// と雑に扱う。
// ============================================================

int bmatching_on_components(
    const CompTree& ct,
    bool capTwo
) {
    int m = ct.m;

    // dp[v][parent edge selected?]
    vector<array<int, 2>> dp(m);

    function<void(int, int)> dfs =
        [&](int v, int p) {

            int base = 0;

            vector<int> gain;

            for (int u : ct.g[v]) {
                if (u == p) continue;

                dfs(u, v);

                base += dp[u][0];

                if (is02(ct.val[v], ct.val[u])) {
                    gain.push_back(
                        1 +
                        dp[u][1] -
                        dp[u][0]
                    );
                }
            }

            sort(
                gain.rbegin(),
                gain.rend()
            );

            int cap;

            if (ct.val[v] == 1) {
                cap = 0;
            } else {
                cap = ct.sz[v];
            }

            if (capTwo) {
                cap = min(cap, 2);
            }

            for (int pe = 0; pe <= 1; pe++) {
                if (pe > cap) {
                    dp[v][pe] = NEG;
                    continue;
                }

                int take = cap - pe;

                int res = base;

                for (
                    int i = 0;
                    i < (int)gain.size() &&
                    i < take;
                    i++
                ) {
                    if (gain[i] > 0) {
                        res += gain[i];
                    }
                }

                dp[v][pe] = res;
            }
        };

    dfs(0, -1);

    return dp[0][0];
}

// ============================================================
// 14.
// 同値成分を縮約し、
//
// 「成分サイズ = 使えるport数」
//
// とみなす。
//
// 境界辺が同じ元頂点に集中していることを無視。
// ============================================================

int wrong14(const Input& in) {
    auto ct = compress_equal(in);

    return min(
        in.n - 1,
        ct.internal +
        bmatching_on_components(
            ct,
            false
        )
    );
}

// ============================================================
// 15.
// 「長い同値列は2頂点程度残せば十分」
//
// 各同値成分の port capacity を高々2に潰す。
// 3個以上の独立portが必要なケースで死亡。
// ============================================================

int wrong15(const Input& in) {
    auto ct = compress_equal(in);

    return min(
        in.n - 1,
        ct.internal +
        bmatching_on_components(
            ct,
            true
        )
    );
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // ======================================
    // ここだけ 1〜15 に変更
    // ======================================
    constexpr int MODE = 10;

    Input in = read_input();

    int ans = 0;

    if (MODE == 1) ans = wrong1(in);
    if (MODE == 2) ans = wrong2(in);
    if (MODE == 3) ans = wrong3(in);
    if (MODE == 4) ans = wrong4(in);
    if (MODE == 5) ans = wrong5(in);
    if (MODE == 6) ans = wrong6(in);
    if (MODE == 7) ans = wrong7(in);
    if (MODE == 8) ans = wrong8(in);
    if (MODE == 9) ans = wrong9(in);
    if (MODE == 10) ans = wrong10(in);
    if (MODE == 11) ans = wrong11(in);
    if (MODE == 12) ans = wrong12(in);
    if (MODE == 13) ans = wrong13(in);
    if (MODE == 14) ans = wrong14(in);
    if (MODE == 15) ans = wrong15(in);

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