1. 程式人生 > 其它 >[Acwing143] 最大異或對

[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<iostream>
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<n;i++){
        cin>>a[i];
        insert(a[i]);
    }
    
    int res = 0;
    for(int i = 0;i<n;i++){
        res = max(res, search(a[i]));
    }
    
    cout<<res<<endl;
    return 0;
}