题目大意
给你n个整数,要你任选两个,使它们的异或结果最大。输出这个结果。
解
从高位往低位处理,便于使异或结果最大。
构建Trie树。
从高位往地位处理,每次优先选与当前位不同的路径(这样和最大),若没有,就选择当前位相同的走下去。
代码
(易懂版本)
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
int n, m, len, w, f[10000009][3], A[1000009], ans, tot, k, l, lans;
char ch;
string s;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &A[i]);
w = 0;//建一个0点用于出发...
for (int j = 30; j >= 0; --j) {
k = (A[i] >> j) % 2; //取二进制下第j位的数字
if (f[w][k] == 0) //w号点是否后面有连向的字符k?否。
f[w][k] = ++tot;//新建一个点tot,w号点连点tot。(tot点代表k)
w = f[w][k]; //走向下一个点
}
}
for (int i = 1; i <= n; ++i) {
w = lans = 0;
for (int j = 30; j >= 0; --j) {
k = (A[i] >> j) % 2;
if (f[w][(k + 1) % 2] != 0) { //选择不同的数字
w = f[w][(k + 1) % 2];
lans += 1 << j; //加上当前位异或后能得到的值
} else {
if (f[w][k] != 0) //相同的数字
w = f[w][k];
else //后面没有了
break;
}
}
ans = max(ans, lans); //取最大值
}
printf("%d", ans);
}
(优化版本)
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int n, m, len, w1, w2, f[10000009][3], A[1000009], ans, tot, flag, k, lans;
char ch;
string s;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf("%d", &A[i]);
w1 = w2 = lans = flag = 0;
for(int j = 30; j>=0; --j){
k = (A[i] >> j) % 2;
if(f[w1][k] == 0) f[w1][k] = ++tot;
w1 = f[w1][k];
if(flag == 0){
if(f[w2][(k+1)%2] != 0) {
w2 = f[w2][(k+1)%2];
lans += 1 << j;
}
else if(f[w2][k] != 0)
w2 = f[w2][k];
else flag = 1;
}
}
ans = max(ans, lans);
}
printf("%d", ans);
}