题面
【题目描述】
在给定的NNN个整数A1,A2……AnA_1,A_2……A_nA1,A2……An中选出两个进行XORXORXOR运算,得到的结果最大是多少?
【输入】
第一行一个整数NNN,第二行NNN个整数A1~ANA_1~A_NA1~AN。
【输出】
一个整数表示答案。
【样例输入】
3
1 2 3
【样例输出】
3
【数据范围】
对于100%100\%100%的数据:N<=105,0<=Ai<231N<=10^5, 0<=A_i<2^{31}N<=105,0<=Ai<231
算法分析
如果用暴力的方法,枚举所有情况,时间复杂度为O(N2)O(N^2)O(N2)
进行XORXORXOR运算时,从高位到低位,如果为111,则让000和其匹配,如果为000,则让111和其匹配。
可以将NNN个数转换为字典树,枚举每一个数,根据其二进制在字典树中查找与其匹配的最大异或值,枚举NNN个数为O(N)O(N)O(N),字典树最大深度为313131,总时间复杂度为O(31N)O(31N)O(31N)。
参考程序
#include<bits/stdc++.h>
#define N 4200000
using namespace std;
int n;
int trie[N][3],tot;
int a[N][35]; //存储每个数的二进制
int ans,p[35];
void pre(int num,int x) //转换为二进制
{
int t=0;
while(x)
{
a[num][t]=x%2; //从低位开始存,高位补0,存满31位
t++;
x=x/2;
}
return;
}
void insert() //对n个数建立字典树
{
for(int i=1;i<=n;i++)
{
int u=0; //根节点
for(int j=30;j>=0;j--) //从高位到低位
{
if(trie[u][a[i][j]]==0) trie[u][a[i][j]]=++tot;
u=trie[u][a[i][j]];
}
}
}
int main()
{
scanf("%d",&n);
int x;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
pre(i,x);
}
insert();
p[0]=1;
for(int i=1;i<=31;i++) //预处理2的次方
p[i]=p[i-1]*2;
for(int i=1;i<=n;i++) //枚举n个数,查找与其异或的最大值
{
int u=0; //根节点
int temp=0;
for(int j=30;j>=0;j--) //贪心,1和0匹配,0和1匹配
{
if(a[i][j]==0)
{
if(trie[u][1]) temp+=p[j],u=trie[u][1];
else u=trie[u][0];
}
else
{
if(trie[u][0]) temp+=p[j],u=trie[u][0];
else u=trie[u][1];
}
}
if(temp>ans) ans=temp;
}
printf("%d\n",ans);
return 0;
}