题目大意:
在给定的 N 个整数
A1,A2,…,AN 中选出两个进行异或运算,得到的结果最大是多少?
解题思路:
我们思考到对于两个数相异或,是先将两数转为二进制数,然后比较同一位上不同为1否则为0,然后观察题目发现每个数的二进制不会超过31位,那么容易想到直接将每个数转为31位二进制存储(不足的补0),于是可以构建一颗Trie树。然后考虑对于每一个数,都在数列中找到一个数使其相异或值最大,我们将查询的这个数也转为31位二进制,贪心的想到从后往前扫,尽量使同一位上的数不同,实在没有节点时就走相同的,若没有节点了就用当前的异或值与ans比较,枚举n个数的情况。最后输出ans就OK了。
Accepted code:
#include<cstdio>
#include<cctype>
#define ll long long
#define N 3200005
using namespace std;
ll trie[N][32],tot,n,a[N];
ll max(ll x,ll y){return x>y?x:y;}
inline ll in()
{
ll f=0;int ag=1;char c=getchar();
while(!isdigit(c)){if (c=='-') ag=-1;c=getchar();}
while(isdigit(c)){f=(f<<3)+(f<<1)+c-48;c=getchar();}
return f*ag;
}
void insert(ll x)
{
int p=0;
for(int k=30;k>=0;k--){
int c=(x>>k)&1;
if(!trie[p][c])trie[p][c]=++tot;
p=trie[p][c];
}
}
void init()
{
n=in();
for(int i=1;i<=n;i++)
a[i]=in(),insert(a[i]);
}
ll calc(ll x)
{
int p=0,v=0; ll ans=0;
for(int k=30;k>=0;k--){
ll c=(x>>k)&1,o=c?0:1;
if(trie[v][o])v=trie[v][o],ans=(ans<<1)|1;
else v=trie[v][c],ans<<=1;
p=trie[p][c];
}
return ans;
}
ll count_ans()
{
ll ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,calc(a[i]));
return ans;
}
int main()
{
init();
printf("%lld\n",count_ans());
return 0;
}