原题连接ios
在给定的N个整数A1,A2……AN中选出两个进行xor(异或)运算,获得的结果最大是多少?函数
输入格式
第一行输入一个整数N。spa
第二行输入N个整数A1~AN。code
输出格式
输出一个整数表示答案。ci
数据范围
1 ≤ N ≤ 10^5,
0 ≤ Ai < 2^31get
输入样例:io
3 1 2 3
输出样例:stream
3
解题关键:循环
由于异或时只有当两个数相同二进制数位上的数字不一样时才会为 1,1 ^ 0 = 1
, 0 ^ 1 = 1
, 0 ^ 0 = 0
, 1 ^ 1 = 0
,因此要找出最大的异或对,就须要让两个数的二进制数位上的数尽量不一样便可。二进制
Q & A :
Q :这里对于 ~i
作一下解释,为何 ~i
能够等价于i >= 0
?
A :-1 在二进制中全是 1,因此 -1 的反码的二进制就全是 0 了,这样当 i--
一直减,减到 -1 的时候就能跳出循环了。(🤪其实并无什么卵用,就只是在关键时候影响一下代码的可读性而已)。
最后,解释一下代码中的Query()
函数中的 res += 1 << i;
的意思。此处截取Y总的解释:若是当前子树中,存在第 i 位和 x 的第 i 位不一样的数,说明答案的第 i 位能够变成 1,就把 res 的第 i 位二进制位变成 1 。
完整AC代码:
#include <iostream> #include <cstdio> using namespace std; const int N = 100010, M = 3100010; int son[M][2], idx; void Insert(int x){ int p = 0; for(int i = 30; ~i; i--){ //~i等价于i >= 0,这里从x二进制的第31位开始枚举每一位上的数,因此这里左移了30位,枚举的是第31位上的数 int u = x >> i & 1; //判断x这个数的第i位上的数是1仍是0 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; i--){ int u = x >> i & 1; //若是u == 1说明第i为上的数为1,若是为0则反之。 if(son[p][!u]){ //判断和x这个数的第i位上不同的数的这个分支是否是存在的。 //若是存在,说明异或出来的这个数的第i位上的数能够为1 res += 1 << i; p = son[p][!u]; } //和x这个数的第i位上不同的数的这个分支不存在 else p = son[p][u]; //不存在就只能让p走向存在的这个分支 } return res; } int main(){ int n, res = 0; cin >> n; //读入数据 for(int i = 0; i < n; i++){ int x; cin >> x; Insert(x); res = max(res, Query(x)); } cout << res << endl; return 0; }