CF1285D
题意:找到一个数使得其与给定数组中所有数的异或值的最大值尽量小。
二进制最值常规套路:从高位到低位贪心。
假设当前考虑的最高位中,数组中仅有 \(0\) 或仅有 \(1\),显然我们只需要在当前位填相同的就可以使当前位的异或结果都为 \(0\)。
又有 \(0\),又有 \(1\) 怎么办呢?这一位的贡献已经不可避免了,我们最高位的二进制值把数组中的数分成两部分。假设选择的数在最高位与第一部分数异或为 \(1\),第二部分异或为 \(0\)。
第二部分在最高位已经小于第一部分了,对答案产生贡献的只有第一部分。分别对两部分的非最高位动态规划取较小的值成为第一部分即可。
为了快速查找下一位的 \(0\),\(1\),我们把数据组织成字典树,就会发现我们这个动态规划的过程事实上一个字典树上的树形dp。
#include <bits/stdc++.h>
using namespace std;
struct Node {
int son[2], ans;
} t[100001 * 31];
int cnt = 1;
void dfs(int x, int now) {
if (!t[x].son[0] && !t[x].son[1]) return;
else if (t[x].son[0] && !t[x].son[1]) dfs(t[x].son[0], now - 1), t[x].ans = t[t[x].son[0]].ans;
else if (t[x].son[1] && !t[x].son[0]) dfs(t[x].son[1], now - 1), t[x].ans = t[t[x].son[1]].ans;
else dfs(t[x].son[0], now - 1), dfs(t[x].son[1], now - 1), t[x].ans = (1 << now) + min(t[t[x].son[0]].ans, t[t[x].son[1]].ans);
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
int p = 1;
for (int j = 30; ~j; --j) {
if (!t[p].son[x >> j & 1]) t[p].son[x >> j & 1] = ++cnt;
p = t[p].son[x >> j & 1];
}
}
dfs(1, 30);
cout << t[1].ans;
return 0;
}

浙公网安备 33010602011771号