結果

問題 No.3732 Labyrinth Maker
コンテスト
ユーザー 👑 kencho
提出日時 2026-07-10 04:26:58
言語 C++23(gcc16)
(gcc 16.1.0 + boost 1.92.0 + ACL)
コンパイル:
g++-16 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
WA  
実行時間 -
コード長 6,751 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,879 ms
コンパイル使用メモリ 365,784 KB
実行使用メモリ 31,872 KB
最終ジャッジ日時 2026-09-19 12:34:42
合計ジャッジ時間 39,534 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge1_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 1
other AC * 48 WA * 11
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

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

struct RNG {
    uint64_t x;
    explicit RNG(uint64_t seed = 0x243f6a8885a308d3ULL) : x(seed) {}

    uint64_t next() {
        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);
        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;
        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;
        return z ^ (z >> 31);
    }

    int uniform(int n) {
        return (int)(next() % (uint64_t)n);
    }
};

void solveCase() {
    int N;
    cin >> N;

    const int V = N * N;

    vector<int> val(V);
    vector<int> row(N, 0), col(N, 0);
    int total = 0;

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            int a;
            cin >> a;
            int r = a % N;

            int id = i * N + j;
            val[id] = r;

            row[i] += r;
            if (row[i] >= N) row[i] -= N;

            col[j] += r;
            if (col[j] >= N) col[j] -= N;

            total += r;
            total %= N;
        }
    }

    if (total != 0) {
        cout << -1 << '\n';
        return;
    }

    // おまけの簡単ケース: 全行が mod 0 なら行ごとに分ける
    bool okRows = true;
    for (int x : row) okRows &= (x == 0);

    if (okRows) {
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (j) cout << ' ';
                cout << i + 1;
            }
            cout << '\n';
        }
        return;
    }

    // おまけの簡単ケース: 全列が mod 0 なら列ごとに分ける
    bool okCols = true;
    for (int x : col) okCols &= (x == 0);

    if (okCols) {
        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (j) cout << ' ';
                cout << j + 1;
            }
            cout << '\n';
        }
        return;
    }

    vector<int> parent(V), order, st;
    vector<int> acc(V), cutId(V), cellComp(V), ans(V);
    vector<int> roots;

    order.reserve(V);
    st.reserve(V);
    roots.reserve(V);

    RNG rng(0x243f6a8885a308d3ULL ^ (uint64_t)N * 0x9e3779b97f4a7c15ULL);

    const int MAX_TRY = 30;

    for (int tc = 0; tc < MAX_TRY; ++tc) {
        fill(parent.begin(), parent.end(), -1);
        order.clear();
        st.clear();

        int root = rng.uniform(V);
        parent[root] = -2;
        order.push_back(root);
        st.push_back(root);

        // ランダム DFS で spanning tree を作る
        while (!st.empty()) {
            int v = st.back();
            int i = v / N;
            int j = v - i * N;

            int cand[4];
            int cnt = 0;
            int u;

            if (i > 0) {
                u = v - N;
                if (parent[u] == -1) cand[cnt++] = u;
            }
            if (i + 1 < N) {
                u = v + N;
                if (parent[u] == -1) cand[cnt++] = u;
            }
            if (j > 0) {
                u = v - 1;
                if (parent[u] == -1) cand[cnt++] = u;
            }
            if (j + 1 < N) {
                u = v + 1;
                if (parent[u] == -1) cand[cnt++] = u;
            }

            if (cnt == 0) {
                st.pop_back();
            } else {
                u = cand[rng.uniform(cnt)];
                parent[u] = v;
                order.push_back(u);
                st.push_back(u);
            }
        }

        // 葉側から mod N の和を見る。
        // acc[v] == 0 なら、その場所で 1 部屋として切る。
        acc = val;
        fill(cutId.begin(), cutId.end(), -1);
        roots.clear();

        for (int t = V - 1; t >= 0; --t) {
            int v = order[t];

            if (acc[v] == 0) {
                cutId[v] = (int)roots.size();
                roots.push_back(v);
            } else {
                int p = parent[v];
                if (p >= 0) {
                    int x = acc[p] + acc[v];
                    if (x >= N) x -= N;
                    acc[p] = x;
                }
            }
        }

        int M = (int)roots.size();
        if (M < N) continue;

        // 各セルがどの cut component に属するかを上から決める。
        vector<int> compParent(M, -1), childCnt(M, 0);
        int rootComp = -1;

        for (int v : order) {
            int cid = cutId[v];

            if (cid >= 0) {
                cellComp[v] = cid;

                int p = parent[v];
                if (p >= 0) {
                    int pc = cellComp[p];
                    compParent[cid] = pc;
                    ++childCnt[pc];
                } else {
                    rootComp = cid;
                }
            } else {
                cellComp[v] = cellComp[parent[v]];
            }
        }

        if (rootComp < 0) continue;

        // M 個の 0-mod component を、木上で葉から親にマージして N 個にする。
        vector<char> alive(M, 1);
        deque<int> q;

        for (int c = 0; c < M; ++c) {
            if (c != rootComp && childCnt[c] == 0) {
                q.push_back(c);
            }
        }

        int aliveCnt = M;

        while (aliveCnt > N && !q.empty()) {
            int c = q.front();
            q.pop_front();

            if (!alive[c] || c == rootComp || childCnt[c] != 0) continue;

            alive[c] = 0;
            --aliveCnt;

            int p = compParent[c];
            if (p >= 0) {
                --childCnt[p];
                if (alive[p] && p != rootComp && childCnt[p] == 0) {
                    q.push_back(p);
                }
            }
        }

        if (aliveCnt != N) continue;

        // alive な component を最終部屋番号 1..N にする。
        vector<int> rep(M, -1), finalId(M, 0);
        int idCnt = 0;

        for (int c = 0; c < M; ++c) {
            if (alive[c]) {
                rep[c] = c;
                finalId[c] = ++idCnt;
            }
        }

        for (int v = 0; v < V; ++v) {
            int c = cellComp[v];

            int y = c;
            while (rep[y] < 0) y = compParent[y];

            int r = rep[y];

            y = c;
            while (rep[y] < 0) {
                int p = compParent[y];
                rep[y] = r;
                y = p;
            }

            ans[v] = finalId[r];
        }

        for (int i = 0; i < N; ++i) {
            for (int j = 0; j < N; ++j) {
                if (j) cout << ' ';
                cout << ans[i * N + j];
            }
            cout << '\n';
        }

        return;
    }

    // 解が存在してもここに来ることがある。
    cout << -1 << '\n';
    return;
}

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

    int T;
    cin >> T;
    while (T--) solveCase();
    return 0;
}
0