最大异或对

思路

  • 异或对处理方法

    • 同 异或 为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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只符华单推人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值