[QOJ 10072] Around the Table

乱搞做法,不喜勿喷。

首先考虑 \(\operatorname{random}\) \(60\) 个排列,一次性询问完,相当于我们现在将一个点和它的两个邻居连一条边,我们要求这个图上的一个哈密顿回路?

然后考虑用一些条件找出来这些邻居。

首先,若 \(u\)\(v\) 在同一次中被返回了 \(1\),则他们不能成为邻居。

这样会筛掉很多的情况。

考虑对于一个 \(u\),若 \(u\) 在某一次询问中被返回 \(1\),那么在它之前的所有的备选的邻居全部不合法,删掉。

然后直接建图过后跑哈密顿回路?

然后用一个 bitset 优化一下时间,然后就过了?

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int n;
int32_t M[MAXN][60];
int P[MAXN];
uint64_t R[MAXN];
bitset<MAXN> B[60];
vector<int> C[MAXN];
set<int> adj[MAXN];
vector<int> sym_adj[MAXN];
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n;
    if (n == 1) { cout << "! 1\n"; cout.flush(); return 0; }
    if (n == 2) { cout << "! 1 2\n"; cout.flush(); return 0; }
    if (n == 3) { cout << "! 1 2 3\n"; cout.flush(); return 0; }
    mt19937 rng(1337);
    for (int q = 0; q < 60; ++q) {
        iota(P + 1, P + n + 1, 1);
        shuffle(P + 1, P + n + 1, rng);
        for (int i = 1; i <= n; ++i) {
            M[P[i]][q] = i;
        }
        cout << "?";
        for (int i = 1; i <= n; ++i) cout << " " << P[i];
        cout << "\n";
        cout.flush();
        int k;
        cin >> k;
        if (k == -1) exit(0);
        B[q].set();
        for (int i = 0; i < k; ++i) {
            int u;
            cin >> u;
            R[u] |= (1ULL << q);
            B[q].reset(u);
        }
    }
    for (int i = 1; i <= n; ++i) {
        bitset<MAXN> cand;
        cand.set();
        for (int q = 0; q < 60; ++q) {
            if ((R[i] >> q) & 1) {
                cand &= B[q];
            }
        }
        cand.reset(i);
        for (int j = cand._Find_first(); j < cand.size(); j = cand._Find_next(j)) {
            if (i < j) {
                bool ok = true;
                for (int q = 0; q < 60; ++q) {
                    if (((R[i] >> q) & 1) && M[i][q] > M[j][q]) { ok = false; break; }
                    if (((R[j] >> q) & 1) && M[j][q] > M[i][q]) { ok = false; break; }
                }
                if (ok) {
                    C[i].push_back(j);
                    C[j].push_back(i);
                }
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        int sz = C[i].size();
        for (int x = 0; x < sz; ++x) {
            int v1 = C[i][x];
            for (int y = x + 1; y < sz; ++y) {
                int v2 = C[i][y];
                bool ok = true;
                for (int q = 0; q < 60; ++q) {
                    if (!((R[i] >> q) & 1)) {
                        if (M[v1][q] > M[i][q] && M[v2][q] > M[i][q]) {
                            ok = false;
                            break;
                        }
                    }
                }
                if (ok) {
                    adj[i].insert(v1);
                    adj[i].insert(v2);
                }
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int v : adj[i]) {
            if (adj[v].count(i)) {
                sym_adj[i].push_back(v);
            }
        }
    }
    vector<int> path;
    vector<bool> vis(n + 1, false);
    struct State {
        int u;
        size_t idx;
    };
    vector<State> st;
    int start = 1;
    st.push_back({ start, 0 });
    vis[start] = true;
    path.push_back(start);
    bool found = false;
    while (!st.empty()) {
        if (path.size() == (size_t)n) {
            bool connects = false;
            for (int v : sym_adj[st.back().u]) {
                if (v == start) { connects = true; break; }
            }
            if (connects) {
                found = true;
                break;
            }
            else {
                st.back().idx = sym_adj[st.back().u].size();
            }
        }
        if (st.back().idx < sym_adj[st.back().u].size()) {
            int v = sym_adj[st.back().u][st.back().idx++];
            if (!vis[v]) {
                vis[v] = true;
                path.push_back(v);
                st.push_back({ v, 0 });
            }
        }
        else {
            vis[st.back().u] = false;
            path.pop_back();
            st.pop_back();
        }
    }
    cout << "!";
    if (found)
        for (int x : path) cout << " " << x;
    else
        for (int i = 1; i <= n; ++i) cout << " " << i;
    cout << "\n";
    cout.flush();

    return 0;
}
posted @ 2026-06-13 08:52  To_string  阅读(8)  评论(0)    收藏  举报