题意:n个元素中有两个是特别的,"不特别的"元素都是x,"特别的"都是y,且x≠y,现在你可以最多询问最多19次找到特别的元素的位置
询问可以询问一个子集元素的异或和,n<=1000,ai<=1e9
Sol:
第一次见到这种题呢,长见识了desu...
考虑如果只有一个怎么做,只要得到了一个子集的异或和就能知道特殊的是否在这个集合里,于是可以二进制分组然后确定每一位,需要操作logn次
两个怎么办呢,首先还是二进制分组,我们可以用logn的代价知道两个特殊元素的二进制位中哪几个相同/不同
然后随便找一个不同的位,这一位是1的集合中一定只有一个特殊的,按照只有一个的做一遍就能确定其中一个特殊元素的精确位置,另一个也就可以推算出来了
然后这个题...询问完成后还要...清空什么东西...没看懂反正跟解题思路无关
Code:
#include<bits/stdc++.h>
#define debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
const int maxn = 1009;
int n,x,y,bit,pos,ans1,ans2;
bool vis[maxn];
int a[maxn],b[maxn];
int main()
{
scanf("%d%d%d",&n,&x,&y);
int tmp=n;
while(tmp){bit++;tmp>>=1;}
for(int i=0;i<bit;i++)
{
int cnt=0;
for(int j=1;j<=n;j++) if(j&(1<<i)) a[++cnt]=j;
printf("? %d",cnt);
for(int j=1;j<=cnt;j++) printf(" %d",a[j]);
puts("");
fflush(stdout);
int res;scanf("%d",&res);
if(cnt&1) vis[i]=(res==x); // true for same
else vis[i]=(res==0);
}
for(int i=0;i<bit;i++) if(!vis[i]){pos=i;break;}
for(int i=1;i<=n;i++) if(i&(1<<pos)) a[++a[0]]=i;
ans1=1<<pos;
for(int i=0;i<bit;i++)
{
if(pos==i) continue;
int cnt=0;
for(int j=1;j<=a[0];j++) if(a[j]&(1<<i)) b[++cnt]=a[j];
if(cnt==0) continue;
printf("? %d",cnt);
for(int j=1;j<=cnt;j++) printf(" %d",b[j]);
puts("");
fflush(stdout);
int res;scanf("%d",&res);
if(cnt&1){if(res!=x) ans1|=(1<<i);}
else{if(res!=0) ans1|=(1<<i);}
}
for(int i=0;i<bit;i++)
if(vis[i]){if(ans1&(1<<i)) ans2|=(1<<i);}
else{if(!(ans1&(1<<i))) ans2|=(1<<i);}
printf("! %d %d\n",min(ans1,ans2),max(ans1,ans2));
return 0;
}