1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| #include <bits/stdc++.h> using namespace std;
static constexpr size_t N = 100; static mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
static inline size_t randint(size_t l, size_t r) { return uniform_int_distribution<size_t>(l, r)(rng); }
static inline tuple<size_t, size_t, size_t> randtriple(size_t n) { size_t u, v, w; do u = randint(1, n), v = randint(1, n), w = randint(1, n); while (u == v || u == w || v == w); return {u, v, w}; }
static inline size_t ask_count_of_edges(size_t u, size_t v, size_t w) { cout << "? " << u << ' ' << v << ' ' << w << endl; size_t res; cin >> res; return res; }
int main() { cin.tie(nullptr)->sync_with_stdio(false); set<size_t> nodes; vector<vector<size_t>> adj(N + 1, vector<size_t>(N + 1, numeric_limits<size_t>::max()));
for (size_t i = 1; i <= N; ++i) adj[i][i] = 0;
while (nodes.empty()) { auto [u, v, w] = randtriple(N); size_t cnt = ask_count_of_edges(u, v, w); if (cnt == 0) { nodes.insert({u, v, w}); adj[u][v] = adj[v][u] = adj[u][w] = adj[w][u] = adj[v][w] = adj[w][v] = 0; } else if (cnt == 3) { nodes.insert({u, v, w}); adj[u][v] = adj[v][u] = adj[u][w] = adj[w][u] = adj[v][w] = adj[w][v] = 1; } }
vector<size_t> others; for (size_t x = 1; x <= N; ++x) if (!nodes.count(x)) others.push_back(x); shuffle(others.begin(), others.end(), rng);
for (const size_t x : others) { if (nodes.count(x)) continue;
array<size_t, 2> known{};
vector<vector<size_t>> works; for (const size_t u : nodes) works.emplace_back(1, u);
while (works.size() > 1) { vector<vector<size_t>> new_works; for (size_t i = 0; i < works.size(); i += 2) { if (i + 1 == works.size()) { new_works.push_back(move(works[i])); continue; }
const auto &a = works[i], &b = works[i + 1]; size_t u = a[0], v = b[0]; size_t cnt = ask_count_of_edges(u, v, x), s = numeric_limits<size_t>::max();
if (cnt - adj[u][v] == 0) { s = 0; } else if (cnt - adj[u][v] == 2) { s = 1; } else { new_works.emplace_back(a.rbegin(), a.rend()); new_works.back().insert(new_works.back().end(), b.begin(), b.end()); continue; }
for (size_t j = 0; j < a.size(); ++j) known[s ^ (j & 1)] = a[j], adj[a[j]][x] = adj[x][a[j]] = s ^ (j & 1); for (size_t j = 0; j < b.size(); ++j) known[s ^ (j & 1)] = b[j], adj[b[j]][x] = adj[x][b[j]] = s ^ (j & 1); }
works = std::move(new_works); shuffle(works.begin(), works.end(), rng); }
if (works.size() == 1) { const auto &work = works[0]; size_t s = numeric_limits<size_t>::max(); if (work.size() > 2) { size_t u = work[0], v = work[2]; size_t cnt = ask_count_of_edges(u, v, x); s = cnt - adj[u][v]; assert(s == 0 || s == 2); s >>= 1; } else if (work.size() == 2) { size_t u = work[0], v = known[0] ? known[0] : known[1]; assert(v != 0); size_t cnt = ask_count_of_edges(u, v, x); s = cnt - adj[u][v] - adj[v][x]; assert(s == 0 || s == 1); } else { assert(work.size() == 1); for (size_t v : known) { if (v == 0) continue; size_t u = work[0]; size_t cnt = ask_count_of_edges(u, v, x); s = cnt - adj[u][v] - adj[v][x]; if (s == 0 || s == 1) break; } assert(s == 0 || s == 1); } for (size_t j = 0; j < work.size(); ++j) adj[work[j]][x] = adj[x][work[j]] = s ^ (j & 1); }
nodes.insert(x); }
cout << "!" << '\n'; for (size_t i = 1; i <= N; ++i) { for (size_t j = 1; j <= N; ++j) { assert(adj[i][j] != numeric_limits<size_t>::max()); cout << adj[i][j]; } cout << '\n'; } cout << flush; return 0; }
|