思路
-
异或对处理方法
-
同 异或 为0
-
不同 异或 为1
-
举例
-
0 0 -->0
-
1 1 -->0
-
1 0-->1
-
-
-
十进制的异或处理方法
-
1.先转为2进制
-
2.2进制进行异或处理
-
-
暴力做法
-
for(int i=0;o<n;i++) { for(int j=0;j<n;j++) { res=max(res,a[i]^a[j]); } }
-
-
优化
-
思路
-
1.Ai Bi
-
2.求异或后值最大的条件
-
1.高位优先 有1 有0
-
2.当Ai本位为1,Bi该位为0
-
3.当Ai本位为0,Bi该位为1
-
-
4.使用Trie树插入数据-叶结点存储二进制每一位
-
5.知Ai根据Trie树找Bi
-
使得 该Ai可获得的最大异或值 的Bi
-
每一层按照求异或后值最大的条件判断找Bi有满足条件的选择无走唯一路径
-
-
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
const int M = 3e6+10;
int son[M][2]; //tire树中每个点的所有儿子
int idx ,n;//idx相当于地址的映射表示第几个插入的结点
int a[N];
int insert(int x) //向tire插入数据
{
int p = 0;//根结点
for (int i = 30; i>=0; i--) //i>=0 等效于~i
{//取X的第i位的二进制数是什么 x>>k&1(前面的模板->取x的第k位的二进制数)
int& s = son[p][x >> i & 1];
if (!s) s = ++idx;//如果插入中发现没有该子节点,开出这条路
p = s; //idx当前点的下标 ++idx下个点的下标,因此为创建一个新结点
/*
* 1.p=0w为根结点
* 2.根节点开始p[0][i位的二进制],根节点不对数据进行操作
* 3.根节点向下到达叶子结点是,首先判断有无该结点,无则创建该结点
* 同时因为 s的数据类型是引用数据类型,
* 因此对s的更改即为对 son[p][x >> i & 1]的更改
* 4.s=++idx --> son[父][存储数据内容]=++idx(下个结点的位置)
* 5.p=s 更新下一次循环使用的父节点 (将当前的子赋值给父让下一轮使用)
*/
}
}
//找到tire树上与x异或值最大
int query(int x)
{
int res = 0, p = 0;//res为最大值,p为树上的指针
for (int i = 30; i>=0; i--)
{
int s = x >> i & 1; //让s为x的二进制的第i位,
//!s 取非因为我们要找的与s不同的值的,即为s为1找0 s为0找1
//也就是去找同层有无另一个存放0/1的枝
//因此导致的情况就是 if进入条件成立后进入后res为异或后的一位的值,该值必为 1 0 / 0 1结果
//因为上一步的操作有!s要!s 没有则会进入else
if (son[p][!s])//如果进入if (son[p][!s])这个语句时,说明当前位置两个数不同异或完的结果是1
{//2进制转为10进制 ,res 为十进制的数据,得到异或后的该为的数据进行逐层操作,一次for操作一位
res += 1 << i;//res=2^i
//res 这位就是1 所以加上;else 里的情况 res 这位是0 所以不用加
p = son[p][!s];//子的idx赋值给新父
}
else p = son[p][s];
}
return res;
}
int main()
{
scanf("%d",& n);
//向tire树插入数据
for (int i = 0; i < n; i++)
{
scanf("%d",&a[i]);
insert(a[i]);
}
int res = 0;//记录最大值,起max会和函数重名
//在树上找异或的最大值
for (int i = 0; i < n; i++) res = max(res, query(a[i]));
printf("%d\n",res);
return 0;
}