cf613 Dr. Evil Underscores 01字典樹

傳送門

題意

n個數,找一個數x使得x與每個數的異或的最大值最小。
n<=1e5,0=<ai<=2301n<=1e5,0=<a_i<=2^{30}-1

思路

首先每個數全寫成二進制的形式,我們可以發現,當第i位上全都相同(同1同0),這一位對最終的max可以沒有貢獻,讓x的這一位與其一樣就抵消了,但是如果2個不一樣,那麼肯定這一位是不能抵消掉的,抵消了這一部分,然後那一部分抵消不了。但是對於這一種情況我們到底怎麼選擇,讓最終的答案最小,得由二進制右邊的那些進行了決定才能對於這2種情況做一個選擇。
所以我們用01字典樹來進行存儲,因爲這一位上如果存在不一樣,肯定是隻有這一位相同的分爲一部分,另一些爲一部分。

code

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
template <typename T>
inline T read(){T sum=0,fl=1;int ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fl=-1;
for(;isdigit(ch);ch=getchar())sum=sum*10+ch-'0';
return sum*fl;}
template <typename T>
inline void write(T x) {static int sta[35];int top=0;
do{sta[top++]= x % 10, x /= 10;}while(x);
while (top) putchar(sta[--top] + 48);}
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
template<typename T>T exgcd(T a,T b,T &g,T &x,T &y){if(!b){g = a,x = 1,y = 0;}
else {exgcd(b,a%b,g,y,x);y -= x*(a/b);}}
typedef long long ll;
const ll mod = 1e9+7;

int tr[30*man][2];
int cnt = 0;
void insert(int x){//字典樹插入
    int p = 0;
    for(int i = 29;i >= 0;i--){
        int tp = x>>i&1;
        if(!tr[p][tp])tr[p][tp] = ++cnt;
        p = tr[p][tp];
    }
}

int dfs(int p,int b){//求答案
    if(b<0)return 0;
    if(tr[p][0]==0){//全部爲1
        return dfs(tr[p][1],b-1);
    }else if(tr[p][1]==0){//全部爲0
        return dfs(tr[p][0],b-1);
    }else{//都有,那麼就分2部分找一個最小值。
        return (1<<b) + min(dfs(tr[p][1],b-1),dfs(tr[p][0],b-1));//因爲前面都一樣
        //這一位無論怎麼取,都會有一個2^b的貢獻
    }
}
int main() {
    #ifndef ONLINE_JUDGE
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt","w",stdout);
    #endif
    int n;
    cin >>n;
    for(int i = 1;i <= n;i++){
        int x;
        cin >>x;
        insert(x);
    }   
    cout << dfs(0,29) << endl;
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章