题目描述


分析:

这里先回顾一下异或的操作。异或(Exclusive or, XOR)为当两两数值相同时为否,而数值不同时为真。在编程语言中,常写作 p ^ q。直观如下:


在本题当中可以对给出的 NNN 个整数进行暴力枚举同时记录两两最大的异或结果。很不幸暴力的做法会超时,下面给出暴力代码:

int res = 0
for (int i = 0; i < n; i ++) // 枚举第一个数
{for (int j = 0; j < i; j ++) // 枚举第二个数,可以避免重复枚举res = max(res, a[i] ^ a[j})
}

那我们要进行优化,具体为对内层循环进行优化。由于数据小于 2312^{31}231,因此可以将每个整数看成长度为 313131 位的二进制串。那能使 a[i]a[i]a[i] 与其异或值最大的整数一定是高位至低位有尽可能多的不同位(使异或结果可以尽可能多地获得1)。流程如下所示,假设 a[i]a[i]a[i] 为313131位的二进制数101110...1101110...1101110...1。在贪心准则下每次往能获得最大值的方向走,若其他整数不能使当前位获得最大值(假设 a[i]a[i]a[i] 当前位为0,而tire树中只有0可以走),也只能先将就一下往这里走,等下一位再追求最好的。直至走完 a[i]a[i]a[i]。


:对于 a[i]a[i]a[i] 来讲,它面临的 trie树,是由 a[0]...a[i−1]a[0] ... a[i-1]a[0]...a[i−1] 构建的。
以上就是利用trie树优化内层的循环的思想,并且每次 a[i]a[i]a[i] 只和 a[j](j<i)a[j](j < i)a[j](j<i) 的数进行运算即可,这是因为 p ^ q = q ^ p(^ 为异或运算)。
另外需要注意一个细节,对于每一个 a[i](0≤i≤N)a[i](0≤i≤N)a[i](0≤i≤N)是先进行对其进行最大异或值查询再插入进 trie树还是先插入再查询呢?这里我们采用先插入再查询的流程,因为对于第一个整数来讲,trie树为空,若此时进行异或运算可能会非法的结果;若先插入再查询,则第一个数一定是和自己做异或运算,由于异或运算的性质,可以得出结果一定为000。


别扭的位运算

由于本题都是对二进制数进行操作,因此我打算先提前把位运算说清楚,这样在看代码时会事半功倍。
左移运算(<<):在C++中,若对整数进行左移操作,如 x << 1,即把每一位向前(左)推一位后在末尾补上000,相当于将这个数放大222倍。这是为什么呢?请看下图:


右移运算(>>):在C++中,若对整数进行左移操作,如 x >> 1,即把每一位向后(右)推一位,并把推出去的数去掉,相当于将这个数缩小222倍。具体细节可将左移推导中的乘法转换为除法即可。同理也要搞清楚左移 kkk 位以及右移 kkk 位的含义。

有了左右移的概念之后,我们来看一下代码中经常出现的位运算操作之一:x >> k & 1。大家都将该操作称为“看看第 kkk 位(kkk 从000开始)”。该操作为将 xxx 的二进制表示右移 kkk 位后与0000...010000...010000...01按位求与运算。我想与运算大家肯定明白,那为什么是看看第 kkk 位呢?由于二进制只有000和111,求与运算后若为000,说明第 kkk 位是000;若是111,说明第 kkk 位是111。例见下图:


代码(C++)

#include <iostream>using namespace std;const int N = 100010, M = 31 * N;
int a[N], son[M][2], n, idx;void insert(int x)
{int p = 0;for (int i = 30; i >= 0; i --){// 取出 x 的第 i 位二进制数int u = x >> i & 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 u = x >> i & 1;// 对于当前位的二进制数// 尽可能往其出现过的相反的方向走,假设当前位 u = 0// 若1的那个方向的 trie树枝干被创建则向那个方向走// 若没有被创建,则先将就一下走0的方向if (son[p][!u]){p = son[p][!u];res = (res << 1) + !u; // 将当前位加到左移后空出的第0位上}else {p = son[p][u];res = (res << 1) + u;}}return res;
}int main()
{cin >> n;for (int i = 0; i < n; i ++) cin >> a[i];int res = 0;for (int i = 0; i < n; i ++){// 先插入后运算是为了避免边界问题,对于第一个整数整个树为空// 若先将自己插入进去,则与自己的异或结果始终为0insert(a[i]);int t = query(a[i]);res = max(res, a[i] ^ t);}cout << res;
}

AcWing 143. 最大异或对 —— 神奇的二进制相关推荐

  1. AcWing 143. 最大异或对

    题目连接 https://www.acwing.com/problem/content/145/ 思路 贪心的想,如果我们想找到一个异或的最大值,那么我们肯定想每一位最好都是相反的,如果没有这样的情况 ...

  2. 143. 最大异或对

    模板:tire 复杂度:O(nlogn) 143. 最大异或对 #include <iostream> #include <algorithm> using namespace ...

  3. 143. 最大异或对【贪心 trie】

    贪心,尽可能走不同的路. #include<bits/stdc++.h> using namespace std; const int N=1e5+10; typedef long lon ...

  4. 树状数组-神奇的二进制

    树状数组是解决快速更新以及统计数组某段区间总和,设一个数组A[1-N],需要计算A[M-K]的总和,暴力解法需要O(K-M),如果我们求出sum(1-K)和sum(1-M),那么答案就是sum(1-M ...

  5. 神奇的二进制转换和运算

    二进制的运算 正整数和二进制互转 二进制如何区分正负? 二进制位左边首位为0为正数,例如:6 --->00000110:1为负数,例如:-6---->11111010 正整数转二进制的过程 ...

  6. 数学小魔术——神奇的二进制

    小魔术--猜数游戏 心中默想一个小于50的两位数 接着,我问你在以下的6张卡片中,哪几张卡片中有你想的那个数?(为什么是6张卡片,和50有什么关系) 最后,我不费吹灰之力就能猜出这个数. 这六张卡片有 ...

  7. AcWing基础算法课Level-2 第二讲 数据结构

    AcWing基础算法课Level-2 第二讲 数据结构 单链表 AcWing 826. 单链表3453人打卡 双链表 AcWing 827. 双链表2865人打卡 栈 AcWing 828. 模拟栈3 ...

  8. Acwing算法基础课学习笔记

    Acwing学习笔记 第一章 基础算法 快速排序 归并排序 二分查找 前缀和与差分 差分 位运算 离散化 第二章 数据结构 单链表 双链表 栈 队列 单调栈 单调队列 KMP算法 Trie 并查集 堆 ...

  9. 0x16.基本数据结构 — Trie树(字典树)+ A C 自 动 机

    目录 用TrieTrieTrie树来处理整数异或问题是真的舒服! 一.TrieTrieTrie树 TrieTrieTrie的基本操作 0.初始化 1.插入 2.检索 二.TrieTrieTrie树例题 ...

  10. 0x10基本数据结构

    0x11 栈 栈是一种后进先出的线性数据结构 AcWing 41.包含min函数的栈 维护两个栈,一个记录栈的值,另一个单调栈,记录下当前的最小值即可 coding AcWing 128. 编辑器 开 ...

最新文章

  1. 物联网在“最后一公里”投递中的应用
  2. Linux内核抢占实现机制分析【转】
  3. JavaScript有限状态机实现方式
  4. 树莓派:和电脑之间的串口编程,以及树莓派的备份
  5. 《走遍中国》珍藏版(八)
  6. Openstack的镜像上传原理
  7. Adidas、金拱门、KFC、乐天玛特,零售巨头的选址秘诀都在数据里了
  8. android 动态绘制布局,Android代码和绘制曲线中按钮和绘图板的动态布局
  9. 落户北京经开区 小米汽车首车预计2024年下线并量产 网友:开始存钱!
  10. 计算机科技英语论文,计算机科技英语论文.doc
  11. SSL Library Compare
  12. flash+xml 制作电子相册教程
  13. win7怎么把计算机放到桌面6,手机投屏到电脑win7最简单具体操作步骤
  14. 量子十问之四:“薛定谔猫”为什么会自然死亡?
  15. SpringSecurity登陆受权出现This object has not been built问题解决
  16. 工作中常见的两种谬误
  17. thinkphp5.1和5.0下的中文分词
  18. 前端性能优化之WebP图片
  19. WPF嵌入技术1_嵌入WPF到cad(MFC,win32窗体),Win32API嵌入WPF位置跳走的解决方案
  20. 【多媒体编解码】Openmax IL (一)官方文档概述

热门文章

  1. OKR工作法学习心得
  2. matlab 图像上加边框,matlab代码-图像上画框 | 学步园
  3. 当面试官问到以后的职业规划,这样回答绝对称赞你是高手!(二)
  4. 如何在透视表中同时显示客户编码和客户名称
  5. Php微信拉黑,微信被拉黑或删除?用这个方法强制聊天
  6. 美多次透露加息 国债收益率持续走高
  7. 使用jQuery实现旋转木马效果
  8. 键盘拆开重新安装步骤_笔记本键盘怎么拆——键盘分拆详细步骤
  9. 计算机的复数形式英语,名词的复数形式大全
  10. 麒麟V10 kylin v10服务器版yum软件源官方源亲测可用