zoukankan      html  css  js  c++  java
  • 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 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    P3391 【模板】文艺平衡树(Splay)
    P4198 楼房重建
    P1491 集合位置
    P3957 跳房子
    P4016 负载平衡问题
    bzoj1077: [SCOI2008]天平 差分约束
    bzoj1151: [CTSC2007]动物园zoo 状压dp
    bzoj1076: [SCOI2008]奖励关 状压dp
    bzoj1226: [SDOI2009]学校食堂Dining 状压dp
    bzoj1879: [Sdoi2009]Bill的挑战 状压dp
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/8983276.html
Copyright © 2011-2022 走看看