题意:给你两个数组a和b,让你安排a和b的顺序使得a数组与b数组一一对应得到的异或数组c字典序最小
思路:建01字典树暴力跑最优匹配即可,借鉴标程思想写了一份AC代码,将两个数组建到一颗字典树上,用num数组维护当前节点是否可用,这样便使得删除操作非常容易实现,在匹配的时候利用dfs的性质去暴力匹配即可,复杂度nlogn
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int tree[31*maxn][2];
int a[maxn],b[maxn];
int num[31*maxn][2];
int cnt;
vector<int> ans;
void insert(int x,int d)
{
int now=0;
for(int i=29;i>=0;i--)
{
int op=(x>>i)&1;
if(tree[now][op]==0)
tree[now][op]=++cnt;
now=tree[now][op];
num[now][d]++;
}
}
int get()
{
int now=0;
int res=0;
for(int i=29;i>=0;i--)
{
if(tree[now][0]&&num[tree[now][0]][0])
now=tree[now][0];
else
{
now=tree[now][1];
res|=1<<i;
}
}
return res;
}
int find(int x,int d)
{
int now=0;
int res=0;
for(int i=29;i>=0;i--)
{
int op=(x>>i)&1;
if(tree[now][op]&&num[tree[now][op]][d])
{
now=tree[now][op];
res|=op<<i;
}
else
{
now=tree[now][op^1];
res|=(op^1)<<i;
}
}
return res;
}
void del(int x,int d)
{
int now=0;
for(int i=29;i>=0;i--)
{
int op=(x>>i)&1;
now=tree[now][op];
--num[now][d];
}
}
bool dfs(int x,int d,int pre)
{
while(1)
{
int y=find(x,d^1);
if(y==pre)
{
ans.push_back(x^y);
del(x,d);
del(y,d^1);
return true;
}
if(dfs(y,d^1,x))
return false;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ans.clear();
cnt=0;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
insert(a[i],0);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&b[i]);
insert(b[i],1);
}
while(ans.size()<n)
{
int x=get();
dfs(x,0,-1);
}
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)
{
if(i) printf(" ");
printf("%d",ans[i]);
}
printf("\n");
for(int i=0;i<=cnt;i++)
tree[i][0]=tree[i][1]=0;
}
return 0;
}