源自 IMO2012 D1T3

题面

出了一道交互题,题目文件如下。

Game.zip

题解

我们考虑我们询问的一个集合 $S$。

如果回答为 No 那么其指向 $x \not = S$。

如果回答为 Yes 那么其指向 $x \not = \overline S$。

考虑不断排除。

首先我们发现所有数都是对称的,因此我们可以将它们重新标号。

我们不妨重新标号成 $0,1,\dots,2^K,\dots,m-1$。

我们这样做:

先询问 $K+1$ 次 $2^K$,如果全部都回答 No 那么 $x != 2^K$。

否则,我们在第一次回答 Yes 时停止继续询问。

然后对于每一个 $0 \leq i \leq K-1$,我们询问集合 $S$ 包含所有二进制第 $i$ 位为 $1$ 的 $\leq 2^K - 1$ 的元素。

每个问题的答案指向第 $i$ 位为 $0$ 或 $1$ 的元素 $\not = x$。

它们的并集恰好是一个数,同时还有上面的一次 Yes 的回答,总共 $K+1$ 次,必定包含一句真话。

所以这个数一定不是 $x$,排除掉,重新标号,继续做。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
using namespace std;
int test;
int n,m,K;
vector<int> V;
string s;
int cnt,tmp;
signed main(){
cin>>test;
cin>>n>>m>>K;
m=1<<K;
for(int i=1;i<=n;i++) V.push_back(i);
while((int)V.size()>m){
for(int i=1;i<=K+1;i++){
cout<<1<<" "<<V[m]<<endl;
cin>>s;
if(s=="Yes") break;
}
if(s=="No") V.erase(V.begin()+m);
else{
tmp=0;
for(int i=0;i<K;i++){
cout<<(m>>1)<<" ";
for(int j=0;j<m;j++)
if(j&(1<<i)) cout<<V[j]<<" ";
cout<<endl;
cin>>s;
if(s=="No") tmp|=1<<i;
}
V.erase(V.begin()+tmp);
}
}
cout<<0<<endl;
cout<<m<<" ";
for(int i:V) cout<<i<<" ";
cout<<endl;
return 0;
}