题意:找到一个数使得其与给定数组中所有数的异或值的最大值尽量小。
二进制最值常规套路:从高位到低位贪心。
假设当前考虑的最高位中,数组中仅有 \(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;
}
