Loading

CF1617D2 Too Many Impostors - 交互

题意

\(n\) 个人(保证 \(n\bmod 3=0\)),其中有 \(k\) 个 impostor(保证 \(n< 3k< 2n\))和 \(n-k\) 个 crewmate,但你不知道 \(k\) 具体是多少。你可以询问至多 \(n+6\) 次,每次给出 \(a,b,c(1\le a,b,c\le n)\),你可以得知 \(a,b,c\) 中是 impostor 多还是 crewmate 多。

找到所有的 impostors。

题解

找到任意一个 impostor 和一个 crewmate

一个结论是,对于四个人 \(x,y,z,w\),若询问 \((x,y,z)\)\((y,z,w)\) 得到的结果不同,那么我们可以确定 \(x\)\(w\) 的身份。

将这 \(n\) 个人分成 \(\frac{n}{3}\) 组,第 \(i\) 组是 \((3i-2,3i-1,3i)\)。若某一组中 impostor 更多,则称这一组是 \(1\);否则这一组是 \(0\)

\(\frac{n}{3}\) 次询问得到每组是 \(0\) 还是 \(1\)。由于 \(\frac{n}{3}<k<\frac{2n}{3}\),所以一定存在一组 \(p\) 满足它是 \(0\);也一定存在一组 \(q\) 满足它是 \(1\)

我们询问 \((3p-1,3p,3q-2),(3p,3q-2,3q-1)\)。我们知道,在 \(3p-2,3p-1,3p,3q-2,3q-1,3q\) 中,一定有相邻的四个人 \(x,y,z,w\) 满足 \((x,y,z)\)\((y,z,w)\) 询问的结果不同。根据上面的结论,我们可以在这六个人里找到一个 impostor 和一个 crewmate,使用了 \(\frac{n}{3}+2\) 次操作。

确定所有人的身份

找到了一个 impostor 和一个 crewmate,设它们分别是 \(a\)\(b\)

对于第 \(i\) 组,我们已经知道了它是 \(0\) 还是 \(1\)。不妨设它是 \(0\)。我们询问 \((3i-2,3i-1,b)\),分类讨论这个询问的结果:

  1. 说明 \(3i-2\)\(3i-1\) 都是 impostor。再询问 \((3i,a,b)\) 就可以得到 \(3i\) 的身份。
  2. 说明 \(3i\) 一定是 impostor,且 \(3i-2\)\(3i-1\) 中恰好有一个 impostor。询问 \((3i-2,a,b)\) 就可以得到 \(3i-2\)\(3i-1\) 的身份。

若这一组是 \(1\),类似地分类讨论即可。

总共使用了 \(n+2\) 次操作。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
#define Debug(...) fprintf(stderr,__VA_ARGS__)
typedef long long ll;
const int N=1e4+5;
int Query(int a,int b,int c){
	cout<<"? "<<a<<' '<<b<<' '<<c<<endl;
	int res;cin>>res;
	return res;
}
int T,n,res[N];
int main(){
	cin>>T;
	while(T--){
		cin>>n;
		int _imp=0,_crm=0;
		For(i,1,n/3){
			res[i]=Query(i*3-2,i*3-1,i*3);
			if(res[i]) _crm=i;
			else _imp=i;
		}
		int res1=Query(_imp*3-1,_imp*3,_crm*3-2),res2=Query(_imp*3,_crm*3-2,_crm*3-1),imp,crm;
		if(res[_imp]!=res1) imp=_imp*3-2,crm=_crm*3-2;
		else if(res1!=res2){
			if(res1) imp=_crm*3-1,crm=_imp*3-1;
			else imp=_imp*3-1,crm=_crm*3-1;
		}else imp=_imp*3,crm=_crm*3;
		vector<int> ans;
		ans.push_back(imp);
		For(i,1,n/3){
			if(_imp==i||_crm==i){
				For(j,i*3-2,i*3) if(j!=imp&&j!=crm&&Query(j,imp,crm)==0) ans.push_back(j);
				continue;
			}
			if(res[i]){
				int x=Query(i*3-2,i*3-1,imp);
				if(x){if(Query(i*3,imp,crm)==0) ans.push_back(i*3);}
				else ans.push_back(Query(i*3-2,imp,crm)?i*3-1:i*3-2);
			}else{
				int x=Query(i*3-2,i*3-1,crm);
				if(!x){ans.push_back(i*3-2),ans.push_back(i*3-1);if(Query(i*3,imp,crm)==0) ans.push_back(i*3);}
				else ans.push_back(i*3),ans.push_back(Query(i*3-2,imp,crm)?i*3-1:i*3-2);
			}
		}
		sort(ans.begin(),ans.end());
		cout<<"! "<<ans.size()<<' ';
		for(int x:ans) cout<<x<<' ';
		cout<<endl;
	}
	return 0;
}
posted @ 2021-12-19 12:00  Alan_Zhao_2007  阅读(52)  评论(0编辑  收藏  举报