Codeforces 923C - Perfect Security(01字典树,最小异或)


题目链接&&题目大意

http://codeforces.com/contest/923/problem/C

For given A and P , find the lexicographically smallest message O , for which there exists a permutation π such that O i XOR π ( P i ) = A i for every i.

对给定序列 A P ,找 P 的一个排列 π ,使 A i XOR π ( P i ) = O i 得到的序列 O 字典序最小。


解题思路

贪心,每次找与 A i 做XOR运算结果最小的 P i ,即可保证序列 O 字典序最小。

将序列 P 的每个元素 P i 从高位到低位插到01字典树中。

对序列 A 的每个元素 A i ,从高位到低位,每一步都尝试沿着与 A i 的当前位相同的指针向下访问,若指向空结点,则访问与 A i 当前位相反的指针。根据XOR运算相同得0,不同得1的性质,即可找到与 A i 做XOR运算结果最小的 P i

为满足一一对应XOR的要求,需额外维护每个结点的存储次数 c n t ,每次访问后 c n t - -,用后即删。


AC代码

#include <bits/stdc++.h>
using namespace std;
#define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define RPD(i, b, a) for (int i = (b), i##_end_ = (a); i >= i##_end_; --i)

typedef long long LL;
const int oo = 0x3f3f3f3f;
const int MAXN = 300010;

inline int read()
{
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9'){x = x * 10 + (c - '0'); c = getchar();}
    return x * f;
}

int trie[MAXN * 30][2], cnt[MAXN * 30][2], val[MAXN * 30], tot;
int n, a[MAXN];

void add(int x)
{
    int cur = 0;
    RPD(i, 29, 0){
        int y = (x >> i) & 1;
        if(!trie[cur][y]) trie[cur][y] = ++ tot;
        cnt[cur][y] ++;
        cur = trie[cur][y];
    }
    val[cur] = x;
}

int ask(int x)
{
    int cur = 0;
    RPD(i, 29, 0){
        int y = (x >> i) & 1;
        if(cnt[cur][y]){
            cnt[cur][y] --;
            cur = trie[cur][y];
        }
        else{
            cnt[cur][y ^ 1] --;
            cur = trie[cur][y ^ 1];
        }
    }
    return val[cur];
}

int main()
{
    n = read();
    REP(i, 1, n) a[i] = read();
    REP(i, 1, n){
        int num = read();
        add(num);
    }
    REP(i, 1, n) cout << (a[i] ^ ask(a[i])) << ' ';
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Hrbust_cx/article/details/80957990