結果

問題 No.3506 All Distance is Square Number
コンテスト
ユーザー rumblycascade7
提出日時 2026-04-18 09:21:24
言語 C++23
(gcc 15.2.0 + boost 1.89.0)
コンパイル:
g++-15 -O2 -lm -std=c++23 -Wuninitialized -DONLINE_JUDGE -o a.out _filename_
実行:
./a.out
結果
TLE  
実行時間 -
コード長 6,948 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 3,549 ms
コンパイル使用メモリ 363,468 KB
実行使用メモリ 11,940 KB
最終ジャッジ日時 2026-04-18 09:22:00
合計ジャッジ時間 8,682 ms
ジャッジサーバーID
(参考情報)
judge2_0 / judge3_0
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 13 TLE * 1 -- * 15
権限があれば一括ダウンロードができます

ソースコード

diff #
raw source code

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

static inline bool is_square(int x) {
    if (x <= 0) return false;
    int r = (int)std::sqrt((long double)x);
    while ((r + 1) * (r + 1) <= x) ++r;
    while (r * r > x) --r;
    return r * r == x;
}

struct Edge { int u, v, w; };

struct Constructor {
    int N;
    vector<Edge> edges;
    vector<vector<pair<int,int>>> adj; // (to, eid)
    array<int, 201> used{};
    mt19937_64 rng;
    chrono::steady_clock::time_point t0;
    double time_limit_sec = 8.0;

    explicit Constructor(int n, uint64_t seed): N(n), rng(seed) {
        t0 = chrono::steady_clock::now();
    }

    bool time_up() const {
        double dt = chrono::duration<double>(chrono::steady_clock::now() - t0).count();
        return dt > time_limit_sec;
    }

    void reset_base() {
        edges.clear();
        used.fill(0);
        adj.assign(max(4, N + 1), {});

        if (N >= 2) {
            edges.push_back({1, 2, 16});
            used[16] = 1;
            adj[1].push_back({2, 0});
            adj[2].push_back({1, 0});
        }
        if (N >= 3) {
            edges.push_back({2, 3, 9});
            edges.push_back({1, 3, 25});
            used[9] = used[25] = 1;
            adj[2].push_back({3, 1});
            adj[3].push_back({2, 1});
            adj[1].push_back({3, 2});
            adj[3].push_back({1, 2});
        }
    }

    bool dfs_find(int s, int t, vector<int>& out_path) {
        vector<int> vis(N + 1, 0), path;
        vis[s] = 1;
        bool found = false;

        function<void(int,int)> go = [&](int u, int sum) {
            if (found) return;
            if (u == t) {
                if (is_square(sum)) {
                    out_path = path;
                    found = true;
                }
                return;
            }
            if ((int)path.size() >= N) return;
            for (auto [v, eid] : adj[u]) {
                if (vis[v]) continue;
                vis[v] = 1;
                path.push_back(eid);
                go(v, sum + edges[eid].w);
                path.pop_back();
                vis[v] = 0;
                if (found) return;
            }
        };

        go(s, 0);
        return found;
    }

    bool check_pairs_with_new_vertex(int v) {
        vector<int> tmp;
        for (int i = 1; i < v; ++i) {
            if (!dfs_find(i, v, tmp)) return false;
        }
        return true;
    }

    void add_edge(int u, int v, int w) {
        int id = (int)edges.size();
        edges.push_back({u, v, w});
        adj[u].push_back({v, id});
        adj[v].push_back({u, id});
        used[w] = 1;
    }

    void pop_last_edge() {
        auto e = edges.back();
        edges.pop_back();
        adj[e.u].pop_back();
        adj[e.v].pop_back();
        used[e.w] = 0;
    }

    struct Choice { int a, b, w1, w2; };

    vector<Choice> collect_choices_for_vertex(int v, int target_choices) {
        vector<Choice> out;
        unordered_set<unsigned long long> seen;

        vector<int> free_w;
        for (int x = 1; x <= 200; ++x) if (!used[x]) free_w.push_back(x);
        vector<int> verts(v - 1);
        iota(verts.begin(), verts.end(), 1);

        int trials = (v <= 10 ? 12000 : (v <= 25 ? 5000 : (v <= 50 ? 2200 : 900)));
        uniform_int_distribution<int> dv(0, (int)verts.size() - 1);
        uniform_int_distribution<int> dw(0, (int)free_w.size() - 1);

        for (int it = 0; it < trials && (int)out.size() < target_choices; ++it) {
            if (time_up()) break;
            int a = verts[dv(rng)], b = verts[dv(rng)];
            if (a == b) continue;
            if (a > b) swap(a, b);
            int i1 = dw(rng), i2 = dw(rng);
            if (i1 == i2) continue;
            int w1 = free_w[i1], w2 = free_w[i2];

            unsigned long long key = (unsigned long long)a;
            key = key * 131ULL + (unsigned long long)b;
            key = key * 257ULL + (unsigned long long)min(w1, w2);
            key = key * 257ULL + (unsigned long long)max(w1, w2);
            if (seen.count(key)) continue;
            seen.insert(key);

            add_edge(v, a, w1);
            add_edge(v, b, w2);
            if (check_pairs_with_new_vertex(v)) {
                out.push_back({a, b, w1, w2});
            }
            pop_last_edge();
            pop_last_edge();
        }

        return out;
    }

    bool build_rec(int v) {
        if (time_up()) return false;
        if (v > N) return true;

        int need = (v <= 12 ? 5 : (v <= 25 ? 3 : 1));
        auto choices = collect_choices_for_vertex(v, need);
        if (choices.empty()) return false;

        shuffle(choices.begin(), choices.end(), rng);
        for (auto &c : choices) {
            add_edge(v, c.a, c.w1);
            add_edge(v, c.b, c.w2);
            if (build_rec(v + 1)) return true;
            pop_last_edge();
            pop_last_edge();
        }
        return false;
    }

    bool build() {
        if (N == 1) return false;
        if (N == 2) {
            reset_base();
            edges.resize(1);
            return true;
        }
        reset_base();
        if (N == 3) return true;

        const int restarts = 20;
        for (int rep = 0; rep < restarts; ++rep) {
            if (time_up()) break;
            reset_base();
            if (build_rec(4)) return true;
        }
        return false;
    }

    bool collect_paths(vector<vector<vector<int>>>& paths) {
        paths.assign(N + 1, vector<vector<int>>(N + 1));
        for (int i = 1; i <= N; ++i) {
            for (int j = i + 1; j <= N; ++j) {
                if (!dfs_find(i, j, paths[i][j])) return false;
            }
        }
        return true;
    }
};

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

    int N;
    if (!(cin >> N)) return 0;

    uint64_t seed = chrono::high_resolution_clock::now().time_since_epoch().count();
    Constructor ctor(N, seed);
    vector<vector<vector<int>>> paths;

    if (!ctor.build() || !ctor.collect_paths(paths)) {
        // Deterministic fallback to keep output format parseable.
        int M = max(1, N - 1);
        cout << M << '\n';
        if (N >= 2) {
            for (int i = 1; i < N; ++i) cout << i << ' ' << i + 1 << ' ' << i << '\n';
        } else {
            cout << "1 1 1\n";
        }
        for (int i = 1; i <= N; ++i) {
            for (int j = i + 1; j <= N; ++j) {
                cout << (j - i);
                for (int e = i; e <= j - 1; ++e) cout << ' ' << e;
                cout << '\n';
            }
        }
        return 0;
    }

    cout << (int)ctor.edges.size() << '\n';
    for (auto &e : ctor.edges) cout << e.u << ' ' << e.v << ' ' << e.w << '\n';
    for (int i = 1; i <= N; ++i) {
        for (int j = i + 1; j <= N; ++j) {
            auto &p = paths[i][j];
            cout << p.size();
            for (int eid : p) cout << ' ' << (eid + 1);
            cout << '\n';
        }
    }
    return 0;
}
0