题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1216
题意:
给定一串数字(int范围内),求这些数字的两两最大异或值。
思路:
首先肯定可以暴力枚举,但是O(N^2)的时间复杂度太高,这道题应该使用字典树。将每个数分解成二进制串存储到字典树中,根在高位的方向,容易知道,这棵树的高度为32,每一层对应32位整数的一位。存储的同时去查询当前异或值的大小,经过比较记录最大的异或值。每次查询当前异或值的原则应该是尽量选择与自己当前位不同的路径,再通过一个变量rtn记录这个路径:每向下走一层,rtn就右移一位,如果当前位有与自己当前位相反的节点那么rtn就+1。
参考了某大佬的博客,图非常详细:https://blog.csdn.net/woshinannan741/article/details/51985368
代码:
#include <bits/stdc++.h>
#define fp(PP,QQ,RR) for(int PP = QQ;PP < RR;PP ++)
#define fs(PP,QQ,RR) for(int PP = QQ;PP >= RR;PP --)
#define MAXN 100005
using namespace std;
typedef long long ll;
struct trie{
int trie[MAXN * 2][2],sz;
void init(){
memset(trie,0,sizeof(trie));
sz = 0;
}
void insert(int t){
int u = 0,w;
for(int i = 31;i >= 0;i --){
w = (t >> i) & 1;
if(!trie[u][w]) trie[u][w] = ++ sz;
u = trie[u][w];
}
}
int find(int t){
int u = 0,w,rtn = 0;
for(int i = 31;i >= 0;i --){
w = 1 - (t >> i) & 1;
rtn <<= 1;
if(trie[u][w]){
rtn ++;
u = trie[u][w];
}else{
u = trie[u][w ^ 1];
}
}
return rtn;
}
}tr;
int main(void)
{
int n;
while(scanf("%d",&n) != EOF){
tr.init();
int ans = 0,tmp;
fp(i,0,n){
cin >> tmp;
tr.insert(tmp);
ans = max(ans,tr.find(tmp));
}
cout << ans << endl;
}
return 0;
}