Perfect Security
题目大意
你有两串长度为 的序列,让你对第二串数排列一下,使得这两串数对应的数的异或序列字典序最小(一个数作为一个关键字,而不是一个数的每一位都是关键字)
分析
考虑贪心,让 和最优的
匹配,然后删掉与
匹配的
,然后去匹配
,直到
正确性显然,就不用再证明了
然后就是如何找到与 相匹配的
,并删除它?
考虑将所有的 插入到
字典树中,然后每次插入对路径整体
,查询的时候就是尽可能的从高位开始找到二进制下最相近的状态,然后对查询路径整体
,就完成了上述操作
Code
#include <cstdio>
const int maxn = 3e5 + 10;
int son[maxn * 30][2], siz[maxn * 30][2];
int n, id, temp, a[maxn];
inline int __read()
{
int x(0), t(1);
char o (getchar());
while (o < '0' || o > '9') {
if (o == '-') t = -1;
o = getchar();
}
for (; o >= '0' && o <= '9'; o = getchar()) {
x = (x << 1) + (x << 3) + (o ^ 48);
}
return x * t;
}
inline void insert(int x)
{
int p(0);
for (int i = 30; ~i; --i) {
int sta = x >> i & 1;
if (!son[p][sta]) son[p][sta] = ++id;
siz[p][sta]++;
p = son[p][sta];
}
}
inline int query(int x)
{
int p(0), res(0);
for (int i = 30; ~i; --i) {
int sta = x >> i & 1;
if (!siz[p][sta]) sta ^= 1;
siz[p][sta]--;
p = son[p][sta];
res = (res << 1) | sta;
}
return res ^ x;
}
int main()
{
n = __read();
for (int i = 1; i <= n; ++i) a[i] = __read();
for (int i = 1; i <= n; ++i) {
temp = __read();
insert(temp);
}
for (int i = 1; i <= n; ++i) printf ("%d ", query(a[i]));
} 
京公网安备 11010502036488号