题目链接:http://codeforces.com/contest/948/problem/D
题意:小花的男朋友是个智障 忘记了加密的密码 那么 就像题目前面的一大堆一样 这两句话是没有用的 给n个数字的a数组和n个数字的p数组 对于每一个a[i]在p数组里选一个数字 两者异或得到新的数组c[i] 为了使得c[i]数组的字典序最小 如何安排a[i]与p[]数组中的那个数字异或呢 p[]数组中的值不能重复使用 输出字典序最小的c[]数组 n的大小为3e5 时间为3.5秒 a[i] p[i]的大小都不超过2^30
思路:n^2的跑肯定能跑出来 到那时也一定会超时 题目 友善的给出了a[i]和p[i]的大小 那么灵机一动 给p[]的二进制建造一棵树 让a[i]在树上跑 高位尽量为0的时候数字就尽量小了 但是在怎么控制p[]不重复出现的时候遇见了问题 然后想啊想 真是愧对男朋友教我的AC自动机 然后哭腔求助 被告知每个节点记录一下下面有几个单词通过了 如果现在这个节点还有被通过过 那么就继续向下走就行了 然后-- 很愉快1A
///按照二进制建树 全部建成30层的数 所以要动态建点 不然肯定会爆内存
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
struct NODE
{
int node[9000010][2];
int num[9000010];
int root , l;///l记录当前的结点个数
int new_node()
{
node[l][0] = -1;
node[l][1] = -1;
l++;///根节点的编号是0
return l-1;
}
void init()
{
l = 0;
memset(num , 0 , sizeof(num));
root = new_node();
}
void Insert(int x[])
{
int now = root;
for(int i=0; i<30; i++)
{
if(node[now][x[i]]==-1)
{
node[now][x[i]] = new_node();
}
now = node[now][x[i]];
num[now]++;
}
}
int solve(int x[])
{
int now = root;
int res = 0;
for(int i=0; i<30; i++)
{
res = res*2;
if(node[now][x[i]]!=-1 && num[node[now][x[i]]]!=0)
{
num[node[now][x[i]]]--;
now = node[now][x[i]];
}
else
{
res++;
num[node[now][x[i]^1]]--;
now = node[now][x[i]^1];
}
}
return res;
}
void debug()
{
for(int i=0; i<l; i++)
printf("%d.......%d....\n" , i , num[i]);
}
};
int n;
int a[300010];
int b[30];
NODE trie;
int num;
int main()
{
while( scanf("%d" , &n) != EOF )
{
trie.init();
for(int i=0; i<n; i++)
{
scanf("%d" , &a[i]);
}
for(int i=0; i<n; i++)
{
scanf("%d" , &num);
memset(b , 0 , sizeof(b));
int cnt = 29;
while( num )
{
b[cnt] = num%2;
num/=2;
cnt--;
}
trie.Insert(b);
}
for(int i=0; i<n; i++)
{
memset(b , 0 , sizeof(b));
int cnt = 29;
while( a[i] )
{
b[cnt] = a[i]%2;
a[i]/=2;
cnt--;
}
// trie.debug();
if(i)
printf(" ");
printf("%d" , trie.solve(b));
}
printf("\n");
}
return 0;
}