[Acwing143] 最大异或对


[Acwing143] 最大异或对

  • Trie树

在给定的 \(N\) 个整数 \(A_1,A_2……A_N\)中选出两个进行 \(xor\)(异或)运算,得到的结果最大是多少?

输入格式

第一行输入一个整数 \(N\)

第二行输入 \(N\) 个整数 \(A1~AN\)

输出格式

输出一个整数表示答案。

数据范围

\(1≤N≤10^5\),
\(0≤Ai<2^{31}\)

题解

如果要找到与某个数最大异或的数,最理想的情况是2进制开始每位数字都是相反的。于是我们可以用Trie树将这些数的二进制串储存起来,定义search 操作在树上跑,对于每个节点,假设当前要找的串停在了1,如果节点 0 存在,那么进入0,异或结果就左移一位加上1,如果不存在那么进入节点1,异或结果只左移。

由于\(0 \leq A_i<2^{31}\),Trie深度最多只有\(D = 30\),因此搜索操作时间复杂度是 \(O(D)\) 的常数级别,我们要线性扫描,对每个数找出最大异或值,因此总的时间复杂度是 \(O(Dn)\)。整棵树最多有\(Dn\) 个节点,因此空间复杂度为 \(O(Dn)\)

  • 时间复杂度 \(O(Dn)\)
  • 空间复杂度 \(O(Dn)\)

题解代码

#include
using namespace std;
const int N = 100010,M = 3000300;
int a[N],son[M][2],idx=0;

void insert(int x){
    int p = 0;
    for(int i = 30;i>=0;i--){
        int u = x>>i & 1;
        if(!son[p][u])son[p][u] = ++idx;
        p = son[p][u];
    }
}

//
int search(int x){
    int p=0,res=0;
    //从最高位开始枚举
    for(int i=30;i>=0;i--){
        int u = x>>i & 1;
        if(son[p][!u]){
            p = son[p][!u];
            res = res*2+1;
        }
        else{
            p = son[p][u];
            res = res*2;
        }
    }
    return res;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n;
    cin>>n;

    for(int i=0;i>a[i];
        insert(a[i]);
    }
    
    int res = 0;
    for(int i = 0;i

相关