题目链接
题目解法
考虑子任务
的解法。
令一只变色龙
和其性别不同的变色龙集合
会面,得到结果
,讨论若干情况可得:
、若
,当且仅当
集合中存在与
颜色相同的变色龙,
、否则,当且仅当
集合中存在与
颜色相同或与
存在喜爱关系的变色龙,
因此,可以通过不超过
次操作确定与每一个
有特殊关系的变色龙集合
。
若
,则可以直接确定与其同色的异性变色龙。
否则,
必然为
,组织
与其中的每两个元素进行一次会面,会有恰好一次得到的答案为
,此时没有参与会面的变色龙是
喜欢的变色龙。由此,可以找出所有单向喜欢的关系,确定答案。
对于原题,难点在于如何分离二分图两侧的点集。
但实际上,子任务
解法中的
集合并不一定需要满足所有变色龙都与
性别不同,只需要满足
集合内不存在特殊关系。因此,对于新处理的某条变色龙
,将已有的特殊关系建出二分图,并染色,对
和二分图两侧的变色龙集合都进行子任务
中的过程,即可找到新增的特殊关系。
时间复杂度 ,操作次数不超过 。
#include "chameleon.h"
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3 + 5;
const int Limit = 15000;
bool vis[MAXN];
bool col[MAXN];
int n, cnt, p[MAXN];
vector <int> a[MAXN];
vector <int> b[MAXN];
int ask(vector <int> a) {
cnt++;
return Query(a);
}
int ask(vector <int> a, int x) {
a.push_back(x), cnt++;
return Query(a);
}
void erase(vector <int> &a, int x) {
for (unsigned i = 0; i < a.size(); i++)
if (a[i] == x) {
swap(a[i], a[a.size() - 1]);
a.pop_back();
return;
}
}
void findedge(vector <int> st, int pos) {
for (auto x : a[pos])
erase(st, x);
while (ask(st, pos) != st.size() + 1) {
vector <int> now = st;
while (now.size() != 1) {
vector <int> a, b;
for (unsigned i = 0; i < now.size(); i++)
if (i & 1) a.push_back(now[i]);
else b.push_back(now[i]);
if (ask(a, pos) == a.size() + 1) now = b;
else now = a;
}
int tmp = now.back();
a[pos].push_back(tmp);
a[tmp].push_back(pos);
erase(st, tmp);
}
}
void dfs(int pos, bool type) {
col[pos] = type;
vis[pos] = true;
for (auto x : a[pos])
if (!vis[x]) dfs(x, !type);
}
void Solve(int N) {
n = N;
for (int i = 1; i <= n * 2; i++) {
memset(vis, false, sizeof(vis));
for (int j = 1; j <= i - 1; j++)
if (!vis[j]) dfs(j, true);
vector <int> st;
for (int j = 1; j <= i - 1; j++)
if (col[j]) st.push_back(j);
if (st.size() != 0) findedge(st, i);
st.clear();
for (int j = 1; j <= i - 1; j++)
if (!col[j]) st.push_back(j);
if (st.size() != 0) findedge(st, i);
}
for (int i = 1; i <= n * 2; i++)
assert(a[i].size() == 1 || a[i].size() == 3);
for (int i = 1; i <= n * 2; i++)
if (a[i].size() == 3) {
int x = 0;
if (ask({i, a[i][0], a[i][1]}) == 1) assert(x == 0), x = a[i][2];
if (ask({i, a[i][0], a[i][2]}) == 1) assert(x == 0), x = a[i][1];
if (ask({i, a[i][1], a[i][2]}) == 1) assert(x == 0), x = a[i][0];
assert(x != 0);
b[i].push_back(x);
b[x].push_back(i);
}
memset(vis, false, sizeof(vis));
for (int i = 1; i <= n * 2; i++) {
for (auto x : b[i])
erase(a[i], x);
assert(a[i].size() == 1);
if (vis[i]) continue;
int res = a[i].back();
Answer(i, res);
vis[i] = vis[res] = true;
}
}