题意:给你长度都为n的两个数组a和b,定义ci=ai xor bi,让你任意排列两个数组的顺序,让ci的字典序最小
题解:其实就是贪心的思想,建立两个01字典树,如果两个字典树有相同的边就走相同的边,没有就走不同的边,但是没法保证谁先到后到,所以还得对c数组排一下序
代码借鉴了这里的dfs,后来学长对我说直接跑n次,每次从上往下一条边一条边的往下刮也行。后来想了一下,其实dfs也不是个树形的,因为四个转移条件只能成立其中一个,所以这个dfs也是线性的。。。其实就是类似一个for循环的东西,所以直接写for循环也行。这里的dfs好处就在于每走一遍能刮下来很多条边,所以写起来比较方便
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(s) memset(s, 0, sizeof(s))
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 1e5+5;
const int mod = 998244353;
struct Trie01{
int tot;
int val[32*maxn];
int ch[32*maxn][2],cnt[32*maxn];
void init(){
tot=1;
ch[0][0]=ch[0][1]=0;
cnt[0]=0;
}
void insert(int x){
int u=0;
for(int i=30;i>=0;i--){
int v=(x>>i)&1;
if(!ch[u][v]){
ch[tot][0]=ch[tot][1]=0;
val[tot]=0;cnt[tot]=0;
ch[u][v]=tot++;
}
u=ch[u][v];cnt[u]++;
}
val[u]=x;
}
int query(int x){
int u=0;
for(int i=30;i>=0;i--){
int v=(x>>i)&1;
if(ch[u][v^1])u=ch[u][v^1];
else u=ch[u][v];
}
return val[u];
}
}A,B;
vector<pair<int,int> >ans;
void dfs(int p1,int p2,int x){
int e=min(A.cnt[p1],B.cnt[p2]);
A.cnt[p1]-=e;B.cnt[p2]-=e;
if(A.val[p1]||B.val[p2]){
ans.push_back(make_pair(x,e));
return ;
}
int a1=A.ch[p1][0],a2=A.ch[p1][1],b1=B.ch[p2][0],b2=B.ch[p2][1];
if(A.cnt[a1]&&B.cnt[b1]){
dfs(a1,b1,x<<1);
}
if(A.cnt[a2]&&B.cnt[b2]){
dfs(a2,b2,x<<1);
}
if(A.cnt[a1]&&B.cnt[b2]){
dfs(a1,b2,(x<<1)+1);
}
if(A.cnt[a2]&&B.cnt[b1]){
dfs(a2,b1,(x<<1)+1);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
A.init();B.init();ans.clear();
for(int i=1;i<=n;i++){
int tmp;
scanf("%d",&tmp);
A.insert(tmp);
}
for(int i=1;i<=n;i++){
int tmp;
scanf("%d",&tmp);
B.insert(tmp);
}
dfs(0,0,0);
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++){
for(int j=0;j<ans[i].second;j++){
printf("%d",ans[i].first);
if(j<ans[i].second-1)printf(" ");
}
if(i<ans.size()-1)printf(" ");
}
printf("\n");
}
return 0;
}