題目鏈接
題目解法
考慮子任務 的解法。
令一隻變色龍 和其性別不同的變色龍集合 會面,得到結果 ,討論若干情況可得:
、若 ,當且僅當 集合中存在與 顏色相同的變色龍,
、否則,當且僅當 集合中存在與 顏色相同或與 存在喜愛關係的變色龍,
因此,可以通過不超過 次操作確定與每一個 有特殊關係的變色龍集合 。
若 ,則可以直接確定與其同色的異性變色龍。
否則, 必然爲 ,組織 與其中的每兩個元素進行一次會面,會有恰好一次得到的答案爲 ,此時沒有參與會面的變色龍是 喜歡的變色龍。由此,可以找出所有單向喜歡的關係,確定答案。
對於原題,難點在於如何分離二分圖兩側的點集。
但實際上,子任務 解法中的 集合並不一定需要滿足所有變色龍都與 性別不同,只需要滿足 集合內不存在特殊關係。因此,對於新處理的某條變色龍 ,將已有的特殊關係建出二分圖,並染色,對 和二分圖兩側的變色龍集合都進行子任務 中的過程,即可找到新增的特殊關係。
時間複雜度 ,操作次數不超過 。
#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;
}
}