题面
【题目描述】
在给定的
N
N
N个整数
A
1
,
A
2
…
…
A
n
A_1,A_2……A_n
A1,A2……An中选出两个进行
X
O
R
XOR
XOR运算,得到的结果最大是多少?
【输入】
第一行一个整数
N
N
N,第二行
N
N
N个整数
A
1
~
A
N
A_1~A_N
A1~AN。
【输出】
一个整数表示答案。
【样例输入】
3
1 2 3
【样例输出】
3
【数据范围】
对于
100
%
100\%
100%的数据:
N
<
=
1
0
5
,
0
<
=
A
i
<
2
31
N<=10^5, 0<=A_i<2^{31}
N<=105,0<=Ai<231
算法分析
如果用暴力的方法,枚举所有情况,时间复杂度为
O
(
N
2
)
O(N^2)
O(N2)
进行
X
O
R
XOR
XOR运算时,从高位到低位,如果为
1
1
1,则让
0
0
0和其匹配,如果为
0
0
0,则让
1
1
1和其匹配。
可以将
N
N
N个数转换为字典树,枚举每一个数,根据其二进制在字典树中查找与其匹配的最大异或值,枚举
N
N
N个数为
O
(
N
)
O(N)
O(N),字典树最大深度为
31
31
31,总时间复杂度为
O
(
31
N
)
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;
}