最大异或对
题目链接:ybt高效进阶2-4-2
题目大意
给你一堆数,小于二的三十一次方,问你要你选两个数,使它们异或的值更大。
要你输出这个最大异或值。
思路
我们考虑异或是干嘛的——就是在二进制中相同为 0 0 0,不同为 1 1 1。
那我们要让异或值最大,就是要选出来的数最高位尽可能不同。
那我们可以用 Trie 树,让一个点有两个儿子,分别代表下一位是
0
0
0 还是
1
1
1。
但这时候有个问题,我们是要根节点是最高位还是根节点是最低位呢?
我们想象一下,离根节点越近,它匹配的优先级就越高,那肯定就是越高位,就离根节点越近。
前面的位没有就补
0
0
0。
那我们建树就弄好了,接着看看怎么查询某个数与前面的数匹配。
那首先从根节点下来就是从高位到低位,对于这一位,有不同的就选不同的,不然就看有没有相同的,如果都没有,那后面都是
0
0
0,就可以直接退了。
这个其实就是贪心。
当然如果有不同的才有对答案的贡献。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct Trie {
int son[2], num;
}trie[3200001];
int n, a[100001], x, tmp[32], nn, now, KK, ans, zhi;
void build() {//插入
now = 0;
for (int i = 31; i >= 0; i--) {
if (!trie[now].son[tmp[i]]) {
trie[now].son[tmp[i]] = ++KK;
}
now = trie[now].son[tmp[i]];
}
trie[now].num++;
}
void find() {
now = 0;
zhi = 0;
for (int i = 31; i >= 0; i--) {
if (!trie[now].son[tmp[i] ^ 1]) {//没有跟它这一位不同的
if (trie[now].son[tmp[i]]) {//只有跟它着一位相同的
now = trie[now].son[tmp[i]];
}
else break;//两个都没有,那后面的肯定是全都没有,不如退出
}
else {//有这一位不同的
zhi += 1 << i;//加上这一位的贡献
now = trie[now].son[tmp[i] ^ 1];
}
}
ans = max(ans, zhi);//求出最大值
return ;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
x = a[i];
nn = 0;
memset(tmp, 0, sizeof(tmp));
while (x) {
if (x & 1) tmp[nn++] = 1;
else tmp[nn++] = 0;
x >>= 1;
}
find();
build();
}
printf("%d", ans);
return 0;
}