1. 程式人生 > 實用技巧 >【演算法競賽進階指南】字典樹 The XOR Largest Pair

【演算法競賽進階指南】字典樹 The XOR Largest Pair

題目連結

題意

給出 N 個數字,任意選擇兩個數字進行異或運算,求結果最大值。

思路

我們對於每個數字求與其異或得到的最大值,求這 N 個最大值的最大值。

把每個數字看做一個長度為 32 的二進位制串,將其翻轉,更新到 trie 中。

對於每個二進位制串 \(S\),遍歷其值 \(S_i\)
在 trie 中每次都嘗試向下訪問與 \(S_i\) 相反的字元。
如果能向下訪問那麼向下訪問,當前數字增加 \(1LL<<(31-i)\) ( 字元下標從 0 開始),
否則向下訪問與當前字元相同的節點。

程式碼

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll N=2e6+10;

ll arr[N];
int tot=1,trie[N][2];
ll s[N];
void insert()
{
	ll p=1;
	for(ll i=0;i<32;i++){
		ll now=s[i];
		if(!trie[p][now]){
			trie[p][now]=++tot;
		}
		p=trie[p][now];
	}
}

ll solve()
{
	ll rel=0,p=1,cnt=31;
	for(ll i=0;i<32;i++,cnt--){
		ll now=1^s[i];
		if(trie[p][now]){
			rel+=(1LL<<cnt);
		}else{
			now=s[i];
		}
		p=trie[p][now];
	}	
	return rel;
}

int main()
{
	ll n,rel=0;
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		scanf("%lld",&arr[i]);
		for(ll j=0;j<32;j++){
			s[31-j]=(arr[i]&(1LL<<j))?1:0;
		}
		insert();
		rel=max(rel,solve());
	}
	printf("%lld\n",rel);
	return 0;
}