題意:給你兩個數組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;
}