一、题目
题目描述
给你两个长度为 的数组 ,你可以把 数组任意排列后对应位和 数组异或,求字典序最小的异或结果。
二、解法
很容易看出的贪心,枚举 中的每一个值,找到和 未选中的值异或最小的结果,按顺序输出即可。
可以用一个数据结构维护 数组,异或相关问题我们可以使用 树,我们把 数组拿去建 树,然后把 中的每个值拿去匹配, 树上的每个点维护一个子树中还未被选中个数,就很容易做了。
注意把每一个值拆成长度为 的二进制串,从高位到低位做即可,时间复杂度 。
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 300005;
const int M = 30*N;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,a[M],b[31];
struct trie
{
int cnt,ch[M][2],val[M];
trie() {cnt=1;}
void add(int x)
{
int p=1;
for(int i=30;i>=0;i--)
{
int c=(x>>i)&1;
if(!ch[p][c]) ch[p][c]=++cnt;
p=ch[p][c];val[p]++;
}
}
void solve(int x)
{
int p=1,ans=0;
for(int i=30;i>=0;i--)
{
int c=(x>>i)&1;
if(!val[ch[p][c]]) c^=1;
p=ch[p][c];val[p]--;
ans=(ans<<1)+c;
}
printf("%d ",ans^x);
}
}tr;
int main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
tr.add(read());
for(int i=1;i<=n;i++)
tr.solve(a[i]);
}