CF1033E
题意
交互题。有 \(n\) 个点的无向简单连通图。你不知道这个图。你要通过不超过 \(20000\) 次询问,判断是否是二分图。若是,则输出一种划分方案,否则输出一个奇环。
每次询问你询问一个点集 \(S\),回答是两端都在 \(S\) 中的边数。
\(1\ \leq\ n\ \leq\ 600\)
做法1
如果得到了一棵生成树,则可以确定出每个点的黑白染色,再询问就能判断是否为二分图。
考虑如何得到这棵生成树,可以通过三次询问得到 \(E(A,\ B)\) 表示一端在 \(A\) 中,另一端在 \(B\) 中的边的数量。那么我们可以通过二分的方法找到 \(A,\ B\) 中的这样一条边。
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
int main() {
int n; cin >> n;
auto qry = [&](vector<int> a) {
if(a.size() <= 1) return 0;
cout << "? " << a.size() << endl;
copy(a.begin(), a.end(), ostream_iterator<int>(cout, " "));
fflush(stdout);
int x; cin >> x;
return x;
};
function<pair<int, int>(vector<int>, vector<int>, int)> Q = [&](vector<int> a, vector<int> b, int ea) {
#ifdef DEBUG
cerr << "Q(\n";
cerr << '\t'; for (int u: a) cerr << u << ' '; cerr << endl;
cerr << '\t'; for (int u: b) cerr << u << ' '; cerr << endl;
cerr << '\t' << ea << endl;
cerr << ")\n";
#endif
if(a.size() == 1 && b.size() == 1) return make_pair(a[0], b[0]);
if(b.size() == 1) return Q(b, a, 0);
int t = b.size() >> 1;
vector<int> c, d; c.insert(c.end(), b.begin() + t, b.end()); b.resize(t);
d = a; d.insert(d.end(), c.begin(), c.end());
return qry(d) - ea - qry(c) ? Q(a, c, ea) : Q(a, b, ea);
};
vector<bool> vis(n + 1, 0);
vector<vector<int> > g(n + 1);
vector<int> s(1, 1);
vis[1] = 1;
for (int i = 1; i < n; ++i) {
vector<int> t;
for (int u = 1; u <= n; ++u) if(!vis[u]) t.push_back(u);
auto r = Q(s, t, qry(s));
int u = r.first, v = r.second;
if(!vis[u]) swap(u, v);
vis[v] = 1;
s.push_back(v);
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> a, b, dep(n + 1), par(n + 1);
function<void(int, int, int)> dfs = [&](int u, int p, int d) {
dep[u] = d; par[u] = p;
if(d & 1) a.push_back(u); else b.push_back(u);
for (int v: g[u]) if(v != p) dfs(v, u, d + 1);
return;
};
dfs(1, 0, 0);
int foo, bar;
if(!(foo = qry(a)) && !(bar = qry(b))) {
cout << "Y " << a.size() << endl;
copy(a.begin(), a.end(), ostream_iterator<int>(cout, " "));
return 0;
}
if(!foo) swap(a, b);
function<pair<int, int>(vector<int>)> cyc = [&](vector<int> a) {
if(a.size() == 2) return make_pair(a[0], a[1]);
int t = a.size() >> 1;
vector<int> c;
c.insert(c.end(), a.begin() + t, a.end());
a.resize(t);
if(qry(a)) return cyc(a);
if(qry(c)) return cyc(c);
return Q(a, c, qry(a));
};
function<int(int, int)> lca = [&](int u, int v) {
return u == v ? u : (dep[u] > dep[v] ? lca(par[u], v) : lca(u, par[v]));
};
auto r = cyc(a);
int u = r.first, v = r.second, t = lca(u, v);
cerr << u << ' ' << v << '\t' << t << endl;
vector<int> a1, a2, ans;
while(dep[u] > dep[t]) a1.push_back(u), u = par[u];
while(dep[v] > dep[t]) a2.push_back(v), v = par[v];
ans = a1;
ans.push_back(t);
reverse(a2.begin(), a2.end());
ans.insert(ans.end(), a2.begin(), a2.end());
cout << "N " << ans.size() << endl;
copy(ans.begin(), ans.end(), ostream_iterator<int>(cout, " "));
return 0;
}