思路:
先想暴力的方法,然后进行优化
暴力:
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
// 但其实 a[i] ^ a[j] == a[j] ^ a[i]
// 所以内层循环 j < i // 因为 a[i] ^ a[i] == 0 所以事先把返回值初始化成0 不用判断相等的情况
}
}
利用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就是第一个可以用的下标。
模板参考:Trie字符串统计
代码:
# include<iostream>
# include<algorithm>
# include<cstdio>
using namespace std;
const int N = 100010,M = 3100010;
int son[M][2],idx;
//M代表一个数字串二进制可以到多长
int a[N];
void insert(int x)
{
int p = 0;//根节点
for(int i = 30;i >= 0;i--)
{
int u = x >> i & 1;//取X的第i位的二进制数是什么 x>>k&1(前面的模板)
if(!son[p][u]) son[p][u] = ++idx;//如果插入中发现没有该子节点,开出这条路
p = son[p][u];//指针指向下一层
}
}
int query(int x)
{
int p = 0, res = 0;
//从最大位开始找
for (int i = 30; i >= 0; i -- )
{
int s = x >> i & 1;
if (son[p][!s])//如果当前层有对应的不相同的数
{
res += 1 << i;//*2相当左移一位 然后如果找到对应位上不同的数res+1
p = son[p][!s];//p指针就指到不同数的地址
}
else p = son[p][s];
}
return res;
}
int main()
{
int n;
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 << endl;
return 0;
}