UOJ504 【JOISC2020】变色龙
UOJ504 【JOISC2020】变色龙
交互、二分
先考虑如果知道性别怎么做,容易想到一种二分的方法,枚举一种性别的变色龙,在另一种性别中进行二分,如果不存在颜色相同的变色龙就停止递归,容易发现最终每条变色龙会匹配上\(1\)或\(3\)条变色龙。
如果是\(1\)条,那显然是同色的变色龙;如果是\(3\)条,那么我们将该变色龙与其中的任意两条开会议,只有与同色的变色龙和喜欢自己的变色龙开会时只有\(1\)种颜色,其他情况下都存在\(2\)种颜色,据此我们知道剩下一条变色龙就是自己喜欢的那条,把喜欢关系排除后就解决了问题。
现在我们不知道性别,但是我们可以发现,如果进行二分的集合是独立集,也就是两两之间没有任何关系,我们仍然能够找到其他变色龙与这个独立集之间的边。
那么我们每次暴力枚举独立集,因为每个点度数\(\le 3\),独立集大小必然大于等于\(\frac{n}{4}\),然后进行二分,找出关系,然后递归下去。
我们观察一下复杂度,枚举独立集询问次数为\(O(n \log_{\frac{4}{3}} n)\),而二分边集,每条边会产生\(\log\)次询问,询问次数为\(O(3n \log n)\),剩下分辨\(3\)种关系的过程消耗了\(O(6n)\),由于蒟蒻实现比较逊,卡了一会儿才通过。
\(Code:\)
#include"chameleon.h"
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define N 1005
#define IT vector<int> :: iterator
using namespace std;
int n,m,lo[N],d[N];
bool vis[N][N];
vector<int>e[N];
void calc(int x,vector<int> &q0)
{
if (d[x]==3)
return;
if (q0.size()==1)
{
vis[x][q0[0]]=vis[q0[0]][x]=true;
++d[x],++d[q0[0]];
return;
}
int mid(q0.size()-1 >> 1);
vector<int>q1,q2;
for (int i=0;i<=mid;++i)
q1.push_back(q0[i]);
for (int i=mid+1;i<q0.size();++i)
q2.push_back(q0[i]);
q1.push_back(x);
if (Query(q1)==q1.size())
calc(x,q2); else
{
q1.pop_back(),calc(x,q1),q2.push_back(x);
if (d[x]!=3 && Query(q2)!=q2.size())
q2.pop_back(),calc(x,q2);
}
}
void solve(vector<int> &q0)
{
vector<int>q1,q2;
for (IT it=q0.begin();it!=q0.end();++it)
{
if (d[*it]==3)
continue;
q1.push_back(*it);
if (Query(q1)!=q1.size())
q1.pop_back(),q2.push_back(*it);
}
if (q0.size()==q1.size())
return;
for (IT it=q2.begin();it!=q2.end();++it)
calc(*it,q1);
solve(q2);
}
bool calc(int x,int y,int z)
{
vector<int>q{x,y,z};
return Query(q)==1;
}
void Solve(int zn)
{
srand(1609745220);
n=zn,m=zn << 1;
vector<int>q0;
for (int i=1;i<=m;++i)
q0.push_back(i);
random_shuffle(q0.begin(),q0.end());
solve(q0);
for (int i=1;i<=m;++i)
{
int c0(0),c[3];
for (int j=1;j<=m;++j)
if (vis[i][j])
c[c0++]=j;
if (c0==1)
continue;
if (calc(i,c[0],c[1]))
{
lo[i]=c[2];
continue;
}
if (calc(i,c[0],c[2]))
{
lo[i]=c[1];
continue;
}
lo[i]=c[0];
}
for (int i=1;i<=m;++i)
vis[i][lo[i]]=vis[lo[i]][i]=false;
for (int i=1;i<=m;++i)
for (int j=i+1;j<=m;++j)
if (vis[i][j])
Answer(i,j);
}