题目:http://acm.hdu.edu.cn/showproblem.php?pid=6625
题意:给两个数组,使任意两两配对的异或值字典序最小,输出异或后的数组。
思路:若想使答案最小,应尽量将高位异或掉。按数字二进制从高位到低位建两颗字典树,每次从根开始跑,尽量走相同的路径,实在没有相同路径时,记录当前位的异或值即可。
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+5;
struct Tree{
int tr[32*maxn][2], cnt;
int ed[32*maxn];
void Insert(int x){
int p = 0, v;
for(int i=29; i>=0; i--){
v = (x>>i)&1;
if(!tr[p][v]) tr[p][v] = ++cnt, tr[cnt][0] = tr[cnt][1] = ed[cnt] = 0;
p = tr[p][v]; ed[p] ++;
}
}
}tree1, tree2;
int Find(){
int p1=0, p2=0, x=0;
for(int i=29; i>=0; i--){
int nxt10 = tree1.tr[p1][0], nxt11 = tree1.tr[p1][1];
int nxt20 = tree2.tr[p2][0], nxt21 = tree2.tr[p2][1];
if(tree1.ed[nxt10] && tree2.ed[nxt20]){
p1 = nxt10;
tree1.ed[p1] --;
p2 = nxt20;
tree2.ed[p2] --;
}else if(tree1.ed[nxt11] && tree2.ed[nxt21]){
p1 = nxt11;
tree1.ed[p1] --;
p2 = nxt21;
tree2.ed[p2] --;
}else if(tree1.ed[nxt11] && tree2.ed[nxt20]){
p1 = nxt11;
tree1.ed[p1] --;
p2 = nxt20;
tree2.ed[p2] --;
x += (1<<i);
}else {
p1 = nxt10;
tree1.ed[p1] --;
p2 = nxt21;
tree2.ed[p2] --;
x += (1<<i);
}
}
return x;
}
int t, n, x, ans[maxn];
int main()
{
scanf("%d", &t);
while(t--){
tree1.cnt = tree2.cnt = 0;
tree1.tr[0][0] = tree1.tr[0][1] = tree1.ed[0] = 0;
tree2.tr[0][0] = tree2.tr[0][1] = tree2.ed[0] = 0;
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &x), tree1.Insert(x);
for(int i=1; i<=n; i++) scanf("%d", &x), tree2.Insert(x);
for(int i=1; i<=n; i++) ans[i] = Find();
sort(ans+1, ans+n+1);
for(int i=1; i<=n; i++) printf("%d%c", ans[i], " \n"[i==n]);
}
}