Codeforces835E 二进制乱搞

题意: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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值