D1. Too Many Impostors (easy version)
D2. Too Many Impostors (hard version)
这是一道交互题。
有n个人,分为0、1两类,二者的数量均大于 n/3 小于 2n/3 。
一次询问可以询问三个人(a,b,c)中0的数量多还是1的熟练多,最多进行 2n (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;
}