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 }

 

posted @ 2018-05-02 23:53  Blogggggg  阅读(247)  评论(0编辑  收藏  举报