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;
}
posted @ 2018-10-08 19:53  King_George  阅读(281)  评论(0编辑  收藏  举报