題意:給你長度都爲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;
}