题目描述
在给定的NN个整数A1,A2……AN中选出两个进行xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数N。
第二行输入N个整数A1~AN。
输出格式
输出一个整数表示答案。
数据范围
1≤N≤10 5
0≤Ai<2 31
样例
输入样例:
3
1 2 3
输出样例:
3
方法一:(暴力超时)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=3e6;//M代表一个数字串二进制可以到多长
int a[N];
int n;
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int res=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
res=max(res,a[i]^a[j]);
cout<<res;
return 0;
}
方法二:(trie)(二进制)
(trie树)
trie树中要明确两个问题:
son[N][x]是个啥?idx是个啥?
首先son[N][x]这是个二维数组。
第一维N是题目给的数据范围,像在trie树中的模板题当中N为字符串的总长度(这里的总长度为所有的字符串的长度加起来),在本题中N需要自己计算,最大为N*31(其实根本达不到这么大,举个简单的例子假设用0和1编码,按照前面的计算最大的方法应该是4乘2=8但其实只有6个结点)。
第二维x代表着儿子结点的可能性有多少,模板题中是字符串,而题目本身又限定了均为小写字母所以只有26种可能性,在本题中下一位只有0或者1两种情况所以为2。
而这个二维数组本身存的是当前结点的下标,就是N喽,所以总结的话son[N][x]存的就是第N的结点的x儿子的下标是多少,然后idx就是第一个可以用的下标。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=3e6;//M代表一个数字串二进制可以到多长
int a[N];
int son[M][2],idx;
int n;
int insert(int x)
{
int p=0;//根节点
for(int i=30;i>=0;i--)
{
int s=x>>i&1;/取X的第i位的二进制数是什么 x>>k&1(前面的模板)
if(!son[p][s]) son[p][s]=++idx; ///如果插入中发现没有该子节点,开出这条路
p=son[p][u];//指针指向下一层
}
}
int query(int x)
{
int res=0,p=0;
for(int i=30;i>=0;i--) ///从最大位开始找
{
int s=x>>i&1;
if(son[p][!s])如果当前层有对应的不相同的数
{ ///p指针就指到不同数的地址
res+=1<<i; ///*2相当左移一位 然后如果找到对应位上不同的数res+1 例如 001
/// 010
--->011
p=son[p][!s];
}
else
p=son[p][s];
}
return res;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
insert(a[i]);
}
int res=0;
for(int i=0;i<n;i++)
{
res=max(res,query(a[i]));
}
cout<<res;
return 0;
}