CF948D Perfect Security

题目链接:http://codeforces.com/contest/948/problem/D

知识点:  Trie

题目大意:

  给出两个长度为 (N(1 le N le 300000)) 的数组 (A) 和 (P(0 le A_{i},P_{i} le 2^{30}). 数组 (P) 可置换顺序,置换后得到数组 (B(B_{i} =  A_{i} oplus P_{i})),求能得到的字典序最小的数组 (B).

解题思路:

  把数组 (P) 和 (A) 中的每一个数都视为带有前导零的 (31) 位二进制数。

  将 (P) 中的每一个数由高位到低位插入字典树中。

  依次遍历 (A) 中的每一个数,查询字典树中最适合与这个数异或的数(即二进制表示中不同的位最少并且高位尽可能相同的数),返回这个数(同时在字典树中将该数删除)。

AC代码:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 const int maxn = 300000+5;
 5 int A[maxn];
 6 
 7 struct Trie{
 8     int ch[maxn*30][3];
 9     int val[maxn*30],nm[maxn*30];
10     int sz;
11     Trie(){
12         sz=1;
13         memset(ch[0],0,sizeof(ch[0]));
14         memset(val,0,sizeof(val));
15         memset(nm,-1,sizeof(nm));
16     }
17     void inserts(int num){
18         int u=0;
19         for(int i=30;i>=0;i--){
20             int nx;
21             if(num&(1<<i))
22                 nx=1;
23             else
24                 nx=0;
25             if(!ch[u][nx]){
26                 memset(ch[sz],0,sizeof(ch[sz]));
27                 ch[u][nx]=sz;
28                 sz++;
29             }
30             u=ch[u][nx];
31             val[u]++;   //val 记录经过该结点的数字的个数
32         }
33         nm[u]=num;  //nm 记录该叶子结点对应数字
34     }
35     int query(int num){
36         int u=0;
37         for(int i=30;i>=0;i--){
38             int nx;
39             if(num&(1<<i))
40                 nx=1;
41             else
42                 nx=0;
43             if(ch[u][nx]&&val[ch[u][nx]])
44                 u=ch[u][nx];    //保证高位尽可能相同
45             else
46                 u=ch[u][nx^1];  
47             val[u]--;
48         }
49         return nm[u];
50     }
51 };
52 Trie ac;
53 int main(){
54     int N;
55     scanf("%d",&N);
56     for(int i=0;i<N;i++)
57         scanf("%d",&A[i]);
58     int num;
59     for(int i=0;i<N;i++){
60         scanf("%d",&num);
61         ac.inserts(num);
62     }
63     for(int i=0;i<N;i++){
64         if(i!=0)    printf(" ");
65         printf("%d",ac.query(A[i])^A[i]);
66     }
67     return 0;
68 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
原文地址:https://www.cnblogs.com/Blogggggg/p/8983276.html