【JOISC 2020】【LOJ3274】【UOJ504】变色龙之恋(交互题)(二分)(随机化)

题解:

容易注意到和一个点直接相关的只有三个点。

首先我们想把这三个点找出来。我们可以通过暴力 O ( n 2 ) O(n^2) O(n2) 询问来实现。

稍微优美一点,考虑我们已经找出了前 i − 1 i-1 i1 个点之间的所有连边,由于原图是二分图,所以前 i − 1 i-1 i1 个点我们可以考虑分成两个集合,同一个集合之间没有连边,然后我们可以通过二分找到 i i i 与哪些点在一起时颜色数会减少,进而找到边。

再优美一点,随机化,暴力 Query 分组,然后把所有能找出来的找出来。

然后,我们要确定相连的点中那个和它是同色。

发现直接做很难,不过我们容易发现,当 Query 它,和它同色以及喜欢它的,得到的结果为 1,其他两种方式得到结果为 2,这样可以确定它喜欢的编号,进而确定除了同色以外的所有边。

另外需要注意 L L i = i L_{L_i}=i LLi=i 的情况,这种时候只找得到一条边。


代码:

#include"chameleon.h"
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

//int Query(const std::vector<int> &p);
//void Answer(int a, int b);

using std::cerr;
using std::cout;

int get(int x,std::vector<int> &p){
	int l=0,r=p.size()-1;
	while(l<r){
		int mid=(l+r)>>1;
		std::vector<int> vec;
		vec.push_back(x);
		for(int re i=l;i<=mid;++i)
			vec.push_back(p[i]);
		if(Query(vec)!=(int)vec.size())r=mid;
		else l=mid+1;
	}return l;
}

cs int N=1e3+7;
std::vector<int> G[N];
bool con[N][N],vs[N];

void Solve(int n){
	srand(time(0));
	std::vector<int> A,B;
	for(int i=1;i<=n+n;++i)
		B.push_back(i);
	std::random_shuffle(B.begin(),B.end());
	while(B.size()){
		auto vec=B;A.clear(),B.clear();
		for(int x:vec){
			A.push_back(x);
			if(Query(A)!=(int)A.size())
				A.pop_back(),B.push_back(x);
		}for(int u:B){
			vec=A;vec.push_back(u);
			do{
				vec.pop_back();
				int k=get(u,vec),v=vec[k];
				G[u].push_back(v);
				G[v].push_back(u);
				vec.erase(vec.begin()+k);
				vec.push_back(u);
			}while(Query(vec)!=(int)vec.size());
		}
	}
	for(int re i=1;i<=n+n;++i)
		if(G[i].size()==3){
			int A=G[i][0],B=G[i][1],C=G[i][2];
			if(Query({i,A,B})==1)con[i][C]=con[C][i]=true;
			else if(Query({i,A,C})==1)con[i][B]=con[B][i]=true;
			else con[i][A]=con[A][i]=true;
		}
	for(int re i=1;i<=n+n;++i)
		if(!vs[i])for(int re v:G[i])
			if(!con[v][i])vs[i]=vs[v]=true,Answer(i,v);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值