zoukankan      html  css  js  c++  java
  • [字典树] 树之呼吸-伍之型-最大异或和

    E.树之呼吸-伍之型-最大异或和
    Time Limit: 1000 MS Memory Limit: 32768 K
    Total Submit: 29 (5 users) Total Accepted: 4 (4 users) Special Judge: No
    Description
    在给定的 n 个整数 A1,A2,...,An 中选出两个进行 xor(异或)运算,得到的结果最大是多少?
    Input

    输入第一行为一个正整数 case,表示测试数据组数;

    对于每组测试数据,输入第一行为一个正整数 n,表示给定的整数个数;

    接下来一行给出 n 个整数 A1,A2,...,An;

    保证:

    1 <= case <= 50,1 <= n <= 1e5,0 <= Ai < 2^31;

    ∑n <= 1e6。

    Output
    对于每组测试数据,输出一行一个整数,表示在给定整数中选出两个进行 xor 运算的最大值。
    Sample Input

    2

    5

    1 2 3 4 5

    6

    5 1 8 9 3 1

    Sample Output

    7

    13

    Author
    陈鑫

    题意:在给定的 n 个整数 A1,A2,...,An 中选出两个进行 xor(异或)运算求出最大结果
    思路:若要让2个数的异或结果尽可能的大,则他们每一位数从高位开始要尽可能的不同(什么是高位低位?123中1是相对2和3的高位,3是相对1和2的高位),
    若用每一个数与其他数去比较,则是O(n*n)的复杂度,1e6的n会TLE,所以我们可以对n个数建一颗字典树来求一个数i与这n个数异或的最大值,枚举n个数保存一个最大值作为答案.
    使用二进制来建字典树时,要从数的高位开始向低位建.
    接着枚举第1到第n的数,看哪个数求得的异或值最大,对每个数从这个数的高位往低位在字典树中匹配,
    如果与当前位的数相反的结点存在则访问这个结点并且ans加上2的i-1次幂,否则就访问与当前位的数相同的结点,
    最后保存一个最大的答案并输出

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int amn=1e5+5;
     5 int n,tr[32*amn][2],tot,bit[33],tp; ///每个数有32位,1e5个数,所以要开32*1e5的空间
     6 ll a[amn];
     7 void init(){
     8     memset(bit,0,sizeof bit);
     9     memset(tr,0,sizeof tr);
    10     tot=0;
    11 }
    12 void tobit(ll x){     ///将x转换为2进制数组
    13     tp=0;
    14     while(x){
    15         if(x&1)bit[++tp]=1;     ///x&1表示取出x的最低位的数
    16         else bit[++tp]=0;
    17         x>>=1;  ///x>>1代表x右移一位
    18     }
    19     while(tp<32)bit[++tp]=0;    ///如果二进制数长度不够32则要在高位添0使数
    20 }
    21 void Insert(ll x){
    22     tobit(x);
    23     int rt=0;
    24     for(int i=tp;i>=1;i--){                     ///从高位往低位建树
    25         if(!tr[rt][bit[i]])tr[rt][bit[i]]=++tot;
    26         rt=tr[rt][bit[i]];
    27     }
    28 }
    29 ll query(ll x){
    30     tobit(x);
    31     int rt=0;
    32     ll ans=0,base=1;
    33     for(int i=tp;i>=1;i--){     ///从高位往低位匹配
    34         if(tr[rt][bit[i]^1]){   ///如果与当前位的数相反的结点存在则访问这个结点
    35            rt=tr[rt][bit[i]^1];
    36            ans+=(1<<(i-1));     ///ans加上2的i-1次幂
    37         }
    38         else rt=tr[rt][bit[i]]; ///否则就访问与当前位的数相同的结点
    39     }
    40     return ans;
    41 }
    42 int main(){
    43     int T;scanf("%d",&T);
    44     ll ans;
    45     while(T--){
    46         init();
    47         scanf("%d",&n);
    48         for(int i=1;i<=n;i++){
    49             scanf("%lld",&a[i]);
    50             Insert(a[i]);
    51         }
    52         ans=0;
    53         for(int i=1;i<=n;i++){
    54             ans=max(ans,query(a[i]));   ///保存一个最大的答案来输出
    55         }
    56         printf("%lld
    ",ans);
    57     }
    58 }
    59 /**
    60 题意:在给定的 n 个整数 A1,A2,...,An 中选出两个进行 xor(异或)运算求出最大结果
    61 思路:若要让2个数的异或结果尽可能的大,则他们每一位数从高位开始要尽可能的不同(什么是高位低位?123中1是相对2和3的高位,3是相对1和2的高位),
    62 若用每一个数与其他数去比较,则是O(n*n)的复杂度,1e6的n会TLE,所以我们可以对n个数建一颗字典树来求一个数i与这n个数异或的最大值,枚举n个数保存一个最大值作为答案.
    63 使用二进制来建字典树时,要从数的高位开始向低位建.
    64 接着枚举第1到第n的数,看哪个数求得的异或值最大,对每个数从这个数的高位往低位在字典树中匹配,
    65 如果与当前位的数相反的结点存在则访问这个结点并且ans加上2的i-1次幂,否则就访问与当前位的数相同的结点,
    66 最后保存一个最大的答案并输出
    67 **/
  • 相关阅读:
    CSS的扩展less和sass
    html5小游戏基础知识
    htm5拖放和画布
    htm5
    并查集模板
    二叉树的建树
    kmp的书写
    贪心算法
    容器
    POJ2442 优先队列
  • 原文地址:https://www.cnblogs.com/Railgun000/p/11823314.html
Copyright © 2011-2022 走看看