題目鏈接
題意分析
一看這道題我們 我們第一反應是枚舉然後判斷 但是這樣的複雜度達到了\(O(2^{30}*n)\)
很顯然是過不了的
我們冷靜一波可以發現 如果將每一個數的前15位以及後15位拆開的話 也就是隻考慮15位 這個複雜度是可以接受的
那麼我們可以考慮使用Meet in The Middle
關鍵是匹配該如何匹配
我們對於前十五位 處理出一個序列\(popcount(a1 \bigoplus x)-popcount(ai \bigoplus x)\)
我們對於後十五位 處理出一個序列\(popcount(a1 \bigoplus x)-popcount(ai \bigoplus x)\)
我們把題意轉化一下就可以發現 對於我們要求的x 上下兩個序列是依次互爲相反數的
那麼我們將下面的序列取反 就是\(popcount(ai \bigoplus x)-popcount(a1 \bigoplus x)\) 也就成爲了相等關係
這就成爲了匹配標準
具體實現的時候 可以使用vector存儲系列 然後使用map對於vector進行標記
強大的STL啊!
CODE:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#define N 33000
using namespace std;
int n;bool flag;
int num[N];
vector<int> G;
map<vector<int>,int> vis;
int popcount(int x)
{
int res=0;
while(x)
{
x-=x&-x;
++res;
}
// printf("pop(%d) = %d\n",tmp,res);
return res;
}
int main()
{
scanf("%d",&n);vis.clear();
for(int i=1;i<=n;++i) scanf("%d",&num[i]);
for(int i=0;i<(1<<15);++i)
{
G.clear();
int tmp=popcount(i^(num[1]&((1<<15)-1)));
for(int j=2;j<=n;++j)
{
int x=i^(num[j]&((1<<15)-1));
G.push_back(popcount(x)-tmp);
}
vis[G]=i;
}
for(int i=0;i<(1<<15);++i)
{
G.clear();
int tmp=popcount(i^(num[1]>>15));
for(int j=2;j<=n;++j)
{
int x=i^(num[j]>>15);
G.push_back(tmp-popcount(x));
}
if(vis.count(G))
{
printf("%d\n",(i<<15)+vis[G]);
flag=1;
break;
}
}
if(flag==0) puts("-1");
return 0;
}