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);
}
posted @ 2021-04-13 20:03  GK0328  阅读(80)  评论(0编辑  收藏  举报