0x16 Tire之最大的异或对

我们考虑所有的二元组(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;
}

  

加油啦!加油鸭,冲鸭!!!
原文地址:https://www.cnblogs.com/clarencezzh/p/10778351.html