我们考虑所有的二元组(i,j)且i<j,那么本题的目标就是在其中找到Ai xorAj的最大值。也就是说,对于每个i(1≤i≤N),我们希望找到一个j(1<j<i),使AixorAj最大,并求出这个最大值。
我们可以把每个整数看作长度为32的二进制01串(数值较小时在前边补0),并且把A1~Ai-1对应的32位二进制串插入一棵Trie 树(其中最低二进制位为叶子节点)。接下来,对于Ai对应的32位二进制串,我们在Trie中进行一次与检索类似的过程,每一步都尝试沿着“与Ai的当前位相反的字符指针”向下访问。若与Ai的当前位相反的字符指针”指向空节点,则只好访问与Ai当前位相同的字符指针。根据xor运算“相同得0,不同得1”的性质,该方法即可找出与Ai做xor运算结果最大的Aj。
如下图所示,在一棵插入了2(010), 5(101), 7111)三个数的Trie中,分别查询与6(110), 3(011)做xor运算结果最大的数。(为了简便, 图中使用了3位二进制数代替32位二进制数)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int SIZE=100010; int trie[SIZE*32+5][2], tot = 1; // 初始化,假设字符串由小写字母构成 int a[SIZE], n, ans; void insert(int val) { // 插入一个二进制数 int p = 1; for (int k = 30; k >= 0; k--) { int ch = val >> k & 1; if (trie[p][ch] == 0) trie[p][ch] = ++tot; p = trie[p][ch]; } } int search(int val) { int p = 1; int ans = 0; for (int k = 30; k >= 0; k--) { int ch = val >> k & 1; if (trie[p][ch ^ 1]) { // 走相反的位 p = trie[p][ch ^ 1]; ans |= 1 << k; } else { // 只能走相同的位 p = trie[p][ch]; } } return ans; } int main() { cin>>n; for(int i=1;i<=n;i++) { scanf("%d", &a[i]); insert(a[i]); ans=max(ans, search(a[i])); } cout<<ans<<endl; }