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;
}
posted @ 2021-02-18 18:08  这知识他不进我的脑子  阅读(72)  评论(0编辑  收藏  举报