题意:今天,作为一个友谊礼物,Bakry给予Badawy n个整数a1,a2,...,an,让他去寻找一个数X,使得(underset{1 leq i leq n}{max} (a_i oplus X))最小。
输入:
第一行是一个整数n(1 <= n <= 10^5)
第二行是n个整数a1,a2,...,an(0 <= ai <= 2^30 - 1)
输出:
(underset{1 leq i leq n}{max} (a_i oplus X))的最小值
分析:对于异或最大值,我们可以采用字典树存储每个整数的01串,如果我们要去找一个数X,去查询和每个数的异或最大值,然后比较所有的异或最大值,枚举所有的x,这样会导致超时。我们可以去寻找一种更加棒的方法,当我们去遍历一颗trie树的时候,从高往低遍历每一位,每个结点都有1~2个分支,如果只有一个分支,我们用x异或的时候,我们贪心地希望x这位和这个结点的值相等,这样,我们所能得到的异或最大值会最小,如果有两个分支怎么办,我们去递归求解这两个分支,取一个min,就能得到最小值,同时,我们可以发现,我们可以在递归的时候,顺便把这个最大值求解出来,当只有一个分支的时候,意味着我们要去选择一个x,它的这位是和这个分支的位相等,意味着值为0,如果有两个分支,因为我们求解的是最大值,所以,我们会加上1 << k,这样,我们就可以得到最大值最小了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
using LL = long long;
const int N = 3200005;
const int M = 100005;
int trie[N][2], idx;
int a[M];
void insert(int x)
{
int p = 0;
for (int i = 29; i >= 0; --i)
{
int u = x >> i & 1;
if (!trie[p][u]) trie[p][u] = ++idx;
p = trie[p][u];
}
}
int solve(int cur, int k)
{
if (k == -1)
return 0;
if (trie[cur][0] == 0)
return solve(trie[cur][1], k - 1);
else if (trie[cur][1] == 0)
return solve(trie[cur][0], k - 1);
else
{
return (1 << k) + min(solve(trie[cur][1], k - 1), solve(trie[cur][0], k - 1));
}
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
insert(a[i]);
}
int ans = solve(0, 29);
cout << ans << endl;
return 0;
}