题意:给出一个有n个数的数组a,问是否能找到一个x满足b[i]=a[i]^x。而这个b数组里面所有元素的二进制1的个数都是相等的
a[i]<(2^30)-1
思路:
由数据范围可知,x的范围一定在2^30内,那么我们很容易想到meet in the middle !!!对于30位的搜索折半复杂度为2^15随随便便就能AC啦(硬是WA了4发,还写了巨长时间emmm)
首先我们预处理出前15位的状态,然后跟a数组全部元素做异或操作,那么对于15位后的我们可以取模去掉防止造成影响。
然后我们能得到当前状态异或前15位得到的每个新的元素的1的个数,那么我们统计一下后一位减当前位的差值(为什么这样我一会再说)
那么标记这个 vector数组,这个开个map就行了,顺便还能把当前状态放进去
那么之后就是枚举后15位了,同理我们能得到一个后15位的数组,对于这个数组我们用当前位减去后一位。
那么对于两个互补的数组,他们存在一个关系,一个用后一位减当前位,一个用当前位减后一位,得到的数组会是相同的。
证明其实也不难想:如果他们是互补的,那么他们的顺序一定是相反的。所以就有这个条件!!!
那么如果有满足这样的要求我们就可以得到答案了
详情请见代码!
#include <bits/stdc++.h> using namespace std; #define ll long long #define re register #define pb push_back #define fi first #define se second const int N=2e6+10; void read(int &a) { a=0;int d=1;char ch; while(ch=getchar(),ch>'9'||ch<'0') if(ch=='-') d=-1; a=ch^48; while(ch=getchar(),ch>='0'&&ch<='9') a=(a<<3)+(a<<1)+(ch^48); a*=d; } int a[N],n; vector <int> v; map <vector <int>,int> vis; int ans=-1; void dfs1(int i,int now) { if(i==15) { v.clear(); for(re int j=1;j<=n;j++) v.pb(__builtin_popcount((now^a[j])%(1<<15))); for(re int j=1;j<n;j++) v[j-1]=v[j]-v[j-1]; v.pop_back(); if(!vis.count(v)) vis[v]=now; return; } dfs1(i+1,now); dfs1(i+1,now|(1<<i)); } void dfs2(int i,int now) { if(i==15) { v.clear(); for(re int j=1;j<=n;j++) v.pb(__builtin_popcount(now^(a[j]>>15))); for(re int j=1;j<n;j++) v[j-1]-=v[j]; v.pop_back(); if(vis.count(v)) ans=vis[v]|(now<<15); return; } dfs2(i+1,now); dfs2(i+1,now|(1<<i)); } int main() { read(n); for(re int i=1;i<=n;i++) read(a[i]); dfs1(0,0);dfs2(0,0); printf("%d",ans); return 0; }