题目链接
https://codeforces.com/problemset/problem/1285/D
思路
假设点u的儿子表示的是第k位,那么点u的儿子的就是:左儿子这边的数第k位上是1,右儿子这边的数第k位上是0。
如果点u只有一个儿子,那么我们需要构造的数x的第k位就选这个儿子代表的数(0/1),这样在异或之后就可以相互抵消。
如果点u有两个儿子,那么我们需要构造的数x的第k位无论选什么都会有 2 k 2^{k} 2k的贡献,这时我们要使总答案最小的转移方程为: d p u = m i n ( d p l e f t u , d p r i g h t u ) + 2 k dp_{u} = min(dp_{leftu},dp_{rightu}) + 2^{k} dpu=min(dpleftu,dprightu)+2k
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n;
int a[N];
struct Trie
{
int m, idx;
vector<vector<int>>son;
vector<int>cnt;//记录当前节点有几个儿子
Trie()
{
m = 3e6 + 5;
idx = 0;
son.resize(m, vector<int>(2, 0));
cnt.resize(m, 0);
}
void insert(int x)
{
int p = 0;
for (int i = 30; i >= 0; i--)
{
int &s = son[p][(x >> i) & 1];
if (!s) s = ++idx, cnt[p]++;
p = s;
}
}
} trie;
int dfs(int u, int k)
{
if (!trie.cnt[u] || k < 0)
{
return 0;
}
if (trie.cnt[u] == 2)
{
return (1 << k) + min(dfs(trie.son[u][0], k - 1), dfs(trie.son[u][1], k - 1));
}
else return dfs((trie.son[u][0] == 0 ? trie.son[u][1] : trie.son[u][0]), k - 1);
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
trie.insert(a[i]);
}
cout << dfs(0, 30) << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}