CF 1446 C-Xor Tree
题目链接:https://codeforces.com/contest/1446/problem/C
思路
一个数字选择异或最小的,对于当前位,一定选择数字相同的,例如3的第一位为000000000000000011,那么第一位尽可能地选择0.
可以注意到从高位到低位,如果一个位上既有0又有1,那么该位为0的都和0在一个连通块内,1和1都在一个连通块内,因此同位相同地一定在一个联通块内,特殊情况就是当前位只有一个0或者一个1,必须选择这一位不同的,所以可以保留只有一个0或一个1的情况。那一位全0或者全1那么就是完美的情况。
那么就把所有的数先插入到字典树上,然后暴力考虑对于第i位是保留1还是保留0,dfs一下即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 2e5 * 29 + 10, M = 2e5 + 10;
int a[M], cnt[N];
int tr[N][2], idx, res;
void insert(int x) {
int p = 0;
for(int i = 29; i >= 0; i--) {
int id = (x >> i) & 1;
if(!tr[p][id]) {
tr[p][id] = ++idx;
memset(tr[idx], 0, sizeof tr[idx]);
cnt[idx] = 0;
}
p = tr[p][id];
cnt[p]++;
}
}
void dfs(int p, int sum) {
if(!tr[p][0] && !tr[p][1]) {
res = min(res, sum);
return;
}
// cout << p << " " << sum << endl;
if(tr[p][1]) {
int num = max(cnt[tr[p][0]] - 1, 0);
dfs(tr[p][1], sum + num);
}
if(tr[p][0]) {
int num = max(cnt[tr[p][1]] - 1, 0);
dfs(tr[p][0], sum + num);
}
}
void solve() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
insert(a[i]);
}
res = 1e9;
dfs(0, 0);
printf("%d\n", res);
}
int main() {
// freopen("in.txt", "r", stdin);
solve();
return 0;
}