cf1617D. Too Many Impostors

D1. Too Many Impostors (easy version)
D2. Too Many Impostors (hard version)

这是一道交互题。
有n个人,分为0、1两类,二者的数量均大于 n/3 小于 2n/3 。
一次询问可以询问三个人(a,b,c)中0的数量多还是1的熟练多,最多进行 2
n (easy version) / n+6 (hard version)次询问,要求输出这n个人中所有的0。

easy version:
先做n次询问 (1,2,3), (2,3,4), (3,4,5) … (n-2,n-1,n), (n-1,n,1), (n,1,2),一定存在 i 使得 (i,i+1,i+2) != (i+1,i+2,i+3),那么 i ,i+3 一定为0和1。
不妨令 x = i , y = i+3。只需要再用n次询问 (x,y,1), (x,y,2), (x,y,3) … (x,y,n) 每次的结果就是当前位置的值。
hard version:
先把n个人分成n/3个块 (1,2,3), (4,5,6), (7,8,9) … (n-2,n-1,n),第i个块的询问结果记为 ti。
可以找到两个块 i, j 使得询问结果 (i,i+1,i+2) =0 ,(j,j+1,j+2)=1。
再询问 (i,i+1,j) , (i,i+1,j+1) , (j,j+1,i) , (j,j+1,i+1) ,可以找到一个0的人和一个1的人,记为x,y。
对于每个块,如果ti==0, 则询问(i,i+1,y) 和 (i,i+2,y) ,否则询问 (i,i+1,x) 和 (i,i+2,x) ,就能得到所有人的值。

#include<bits/stdc++.h>
using namespace std;

int query(int x,int y,int z) {
	cout<<"? "<<x<<' '<<y<<' '<<z<<endl;
	int d;
	cin>>d;
	return d;
}

int main() {
	int T;
	cin>>T;
	while(T--) {
		int n;
		cin>>n;
		int a[2]={-1,-1};
		int opr[10005],ans[10005];
		opr[0]=-1;
		for(int i=1;i<=n-2;i+=3) {
			opr[i]=query(i,i+1,i+2);
			if(opr[i]==0) a[0]=i;
			else a[1]=i;
		}
		
		int b[2];		
		int t1,t2;
		t1=query(a[0],a[0]+1,a[1]),t2=query(a[0],a[0]+1,a[1]+1);
		if(t1||t2) b[0]=a[0]+2;
		else b[0]=a[0];
		ans[b[0]]=0;
		t1=query(a[1],a[1]+1,a[0]),t2=query(a[1],a[1]+1,a[0]+1);
		if((1-t1)||(1-t2)) b[1]=a[1]+2;
		else b[1]=a[1];
		ans[b[1]]=1;
		
		for(int i=1;i<=n-2;i+=3) {
			int t=opr[i];
			ans[i]=ans[i+1]=ans[i+2]=t;
			int x=query(i,i+1,b[1-t]),y=query(i,i+2,b[1-t]);
			if(x!=t&&y!=t) ans[i]=1-t;
			if(x!=t&&y==t) ans[i+1]=1-t;
			if(x==t&&y!=t) ans[i+2]=1-t;
		}
		
		int m=0;
		for(int i=1;i<=n;i++) if(ans[i]==0) m++;
		cout<<"! "<<m<<" ";
		for(int i=1;i<=n;i++) if(ans[i]==0) cout<<i<<' ';
		cout<<endl;
		
	}
	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值