题目描述
Problem Description
There are three integer arrays a,b,c. The lengths of them are all N. You are given the full contents of a and b. And the elements in c is produced by following equation: c[i]=a[i] XOR b[i] where XOR is the bitwise exclusive or operation.
Now you can rearrange the order of elements in arrays a and b independently before generating the array c. We ask you to produce the lexicographically smallest possible array c after reordering a and b. Please output the resulting array c.
Input
The first line contains an integer T indicating there are T tests.
Each test consists of three lines. The first line contains one positive integer N denoting the length of arrays a,b,c. The second line describes the array a. The third line describes the array b.
-
T≤1000
-
1≤N≤105
-
integers in arrays a and b are in the range of [0,230).
-
at most 6 tests with N>100
Output
For each test, output a line containing N integers, representing the lexicographically smallest resulting array c.
Sample Input
1
3
3 2 1
4 5 6
Sample Output
4 4 7
Source
2019 Multi-University Training Contest 5
题目大意
给出数组a、b,把ab重排,设ci=ai xor bi
求字典序最小的c
BB
开场-7日神仙最后半小时翻盘
一些很魔幻的做法也许是正解
题解
一个性质:如果a、b、c、d互不相等,且a xor b=c xor d,那么先选ab和先选cd是一样的
所以每次选出一对异或和最小的数即可
很显然可以想到建两棵trie,每次尽量向相同方向跑
这样有个问题:如果当前的两个点都有各两个儿子,那么就会产生分歧,最坏时间为O(n)
因为删点只会影响到log个点,所以很显然(?)可以想到记忆化(?)
欸不是有两个点吗
按照贪心的策略,只有当前的两个点都有各两个儿子时才会产生分歧,否则只会走到一个点上去
若产生分歧则记录当前的方向(0/1),否则随便记一个数,这样就可以给每种走法一个独立的标号,可以在回溯时用hash记录子树中能构成的最小值
随便画一下可以发现,在树还未被改变时,对于一棵树中的一个节点,一定会对应另一个唯一的节点,所以记录路径即可
这样做还是太naive了,我们在身经百战见得多了之后可以发现,too young too simple每一条路径都对应唯一一对点
所以把子树的答案记录在第一棵树的节点上,表示从(该节点,该节点在第二棵树的对应点)往下走能构出的最小值,顺便记录下得出最小值的点对
删除时就从找到的点往上删,把它的祖先全部清空,这样的时间是log的
(其实应该删掉所有包含这两个点之一的点对,但由于两棵树的节点都是一一对应的,所以可以一起做)
第一次暴力的时间是O(n log ai),之后每次是O(log ai),加起来还是O(n log ai)
正确性可以画一下几种情况来感性理解
code
欢迎Hack
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
using namespace std;
int p[32];
int a[100001];
int b[100001];
int A[100001];
int tr[2][3000002][3];
int f[3000002];
int g[3000002][2];
int fa[2][3000002];
int T,n,i,j,k,l;
int len[2];
void clear(int type,int t)
{
tr[type][t][0]=0;
tr[type][t][1]=0;
tr[type][t][2]=0;
fa[type][0]=0;
}
void New(int type,int t,int x)
{
if (!tr[type][t][x])
{
tr[type][t][x]=++len[type];
fa[type][len[type]]=t;
}
}
int dfs(int T,int t1,int t2)
{
int s;
if (T==31)
{
f[t1]=0;
g[t1][0]=t1;
g[t1][1]=t2;
}
if (f[t1]>=0)
return f[t1];
if (tr[0][t1][0] && tr[0][t1][1] && tr[1][t2][0] && tr[1][t2][1])
{
f[t1]=dfs(T+1,tr[0][t1][0],tr[1][t2][0]);
g[t1][0]=g[tr[0][t1][0]][0];
g[t1][1]=g[tr[0][t1][0]][1];
s=dfs(T+1,tr[0][t1][1],tr[1][t2][1]);
if (f[t1]>s)
{
f[t1]=s;
g[t1][0]=g[tr[0][t1][1]][0];
g[t1][1]=g[tr[0][t1][1]][1];
}
}
else
if (tr[0][t1][0] && tr[1][t2][0])
{
f[t1]=dfs(T+1,tr[0][t1][0],tr[1][t2][0]);
g[t1][0]=g[tr[0][t1][0]][0];
g[t1][1]=g[tr[0][t1][0]][1];
}
else
if (tr[0][t1][1] && tr[1][t2][1])
{
f[t1]=dfs(T+1,tr[0][t1][1],tr[1][t2][1]);
g[t1][0]=g[tr[0][t1][1]][0];
g[t1][1]=g[tr[0][t1][1]][1];
}
else
if (tr[0][t1][0] && tr[1][t2][1])
{
f[t1]=dfs(T+1,tr[0][t1][0],tr[1][t2][1]);
f[t1]|=p[T];
g[t1][0]=g[tr[0][t1][0]][0];
g[t1][1]=g[tr[0][t1][0]][1];
}
else
if (tr[0][t1][1] && tr[1][t2][0])
{
f[t1]=dfs(T+1,tr[0][t1][1],tr[1][t2][0]);
f[t1]|=p[T];
g[t1][0]=g[tr[0][t1][1]][0];
g[t1][1]=g[tr[0][t1][1]][1];
}
return f[t1];
}
void del(int type,int t)
{
int A[233],i,j;
j=0;
--tr[type][t][2];
while (t>1)
{
++j;
if (tr[type][fa[type][t]][0]==t)
A[j]=0;
else
A[j]=1;
t=fa[type][t];
if (!tr[type][tr[type][t][0]][2])
tr[type][t][0]=0;
if (!tr[type][tr[type][t][1]][2])
tr[type][t][1]=0;
if (t)
--tr[type][t][2];
}
// fd(i,30,1)
// cout<<A[i];
// cout<<endl;
}
void Del(int t)
{
while (t)
{
f[t]=-1;
g[t][0]=0;
g[t][1]=0;
t=fa[0][t];
}
}
int main()
{
// freopen("02.in","r",stdin);
// freopen("a.out","w",stdout);
p[30]=1;
fd(i,29,1)
p[i]=p[i+1]*2;
memset(f,255,sizeof(f));
scanf("%d",&T);
for (;T;--T)
{
scanf("%d",&n);
fo(i,1,n)
scanf("%d",&a[i]);
fo(i,1,n)
scanf("%d",&b[i]);
clear(0,1);
clear(1,1);
len[0]=1;
len[1]=1;
fo(i,1,n)
{
j=a[i];
fd(k,30,1)
{
A[k]=j&1;
j>>=1;
}
l=1;
fo(k,1,30)
{
New(0,l,A[k]);
l=tr[0][l][A[k]];
++tr[0][l][2];
}
}
fo(i,1,n)
{
j=b[i];
fd(k,30,1)
{
A[k]=j&1;
j>>=1;
}
l=1;
fo(k,1,30)
{
New(1,l,A[k]);
l=tr[1][l][A[k]];
++tr[1][l][2];
}
}
fo(i,1,n)
{
dfs(1,1,1);
if (i<n)
printf("%d ",f[1]);
else
printf("%d",f[1]);
j=g[1][0];
k=g[1][1];
del(0,j);
del(1,k);
Del(j);
}
printf("\n");
fo(i,1,len[0])
{
f[i]=-1;
g[i][0]=0;
g[i][1]=0;
}
}
}