codeforces 1257F

题目链接

题意

有n个数,要求找到一个数x,使得每个数都与x异或后,所有数的二进制表示中的1的数量一样.

数据范围

n ≤ 100 , 0 ≤ 数 , x < 2 30 n\le 100 ,0 \le 数,x< 2^{30} n100,0,x<230

解法

meet in middle

分别搜索x的前15位,用一个结构体存n个数二进制表示下1的个数,然后把搜索的结果存下来,然后搜索后15位,将后15位的结果丢到hash表中.最后枚举前15位的搜索结果,再hash表中查是否有对应的解即可.因为可以任意输出一个解,所以并不复杂.

#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
typedef unsigned long long ull; 
const ull step=233;
inline int read(){
	char c=getchar();int t=0,f=1;
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
struct node{
	int a[105];
}ch[1<<15],ch2[1<<15];
int n,a[maxn],cnt=-1;
const int sz=2e6;
vector<int> ha[sz];
int cnt2=-1,num1[1<<15],num2[1<<15];
void dfs1(int now,int lim,int alfa){
	if(now==lim+1){
		cnt++;
		for(int i=1;i<=n;i++){
			int tmp=a[i]^alfa,tot=0;
			for(int i=0;i<=14;i++){
				if(tmp&(1<<i))tot++;
			}
			ch[cnt].a[i]=tot;	
		}num1[cnt]=alfa;
		return ;
	}
	dfs1(now+1,lim,alfa|(1<<now));
	dfs1(now+1,lim,alfa);
}
void dfs2(int now,int lim,int alfa){
	if(now==lim+1){
		cnt2++;
		for(int i=1;i<=n;i++){
			int tmp=(a[i]^alfa),tot=0;
			for(int i=15;i<=29;i++){
				if(tmp&(1<<i))tot++;
			}
			ch2[cnt2].a[i]=tot;
		}num2[cnt2]=alfa;
		ull sum=0;
		for(int i=1;i<=n;i++){
			sum=sum*step+ch2[cnt2].a[i];
		}
		ha[sum%sz].push_back(cnt2);
		return ;
	}
	dfs2(now+1,lim,alfa|(1<<now));
	dfs2(now+1,lim,alfa);
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)a[i]=read();
	dfs1(0,14,0);
	dfs2(15,29,0);
	for(int i=1;i<=cnt;i++){
		node tmp;
		int mn=0;
		for(int j=1;j<=n;j++){
			mn=max(mn,ch[i].a[j]);
		}
		for(int j=mn;j<=30;j++){
			ull sum=0;
			for(int k=1;k<=n;k++){
				tmp.a[k]=j-ch[i].a[k];
				sum=sum*step+tmp.a[k];
			}
			int pos=sum%sz;
			for(int k=0;k<ha[pos].size();k++){
				int flag=1;
				for(int u=1;u<=n;u++){
					if(ch2[ha[pos][k]].a[u]!=tmp.a[u]){flag=0;break;}
				}
				if(flag){
					printf("%d\n",num1[i]+num2[ha[pos][k]]);return 0;
				}
			}
		}
	}
	puts("-1");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值