题目链接: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.... " , 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(" "); } return 0; }