zoukankan      html  css  js  c++  java
  • NBUT

    [1597] Find MaxXorSum
    时间限制: 2000 ms 内存限制: 65535 K
    问题描述
    Given n non-negative integers, you need to find two integers a and b that a xor b is maximum. xor is exclusive-or.
    输入
    Input starts with an integer T(T <= 10) denoting the number of tests.
    For each test case, the first line contains an integer n(n <= 100000), the next line contains a1, a2, a3, ……, an(0 <= ai <= 1000000000);
    输出
    For each test case, print you answer.
    样例输入
    2
    4
    1 2 3 4
    3
    7 12 5
    样例输出
    7
    11

    题意:给出1e5个数,每个数小于等于1e9,求任意两个值使其异或值最大。

    又是经典的给一堆数求某运算最大问题。也是经典的01字典树求异或和最大问题。听说曾作为今日头条的面试算法问题的开胃菜。

    首先按照每个数的二进制建树,倒着从最高位开始建,因为不超过1e9的值,算每个数的二进制位31位,根节点是最高位,向下叶子节点为最低位。因为在求异或值时要尽量使得高位存在1。这也符合遍历数的顺序。

    建树完成后就开始对每个数遍历,对1e5个数分别从根节点开始走,如果该数的当前位为1,那么查询树上同位是否有数存在0,也就是查询同一个父亲的另一个节点是否存在,如果存在则这一位置1,接着继续按照那个节点往下走,判断下一位和我们遍历的数相比是否存在相反的节点。

    最后得到每一个数可以匹配到的最大异或值,输出即可。

    对于查询的过程,如果对字典树有了解的话,都知道字典树是对单词的记录,查询时按照字符串匹配,不断往下走节点进行操作。 如此看来,01字典树在求异或时也是如此,我们记录了所有数字,现在对于一个要查询的数,求异或,那么就尽量从最高位开始使其在字典树中找到相同位置不同的节点,比如要给出的数是00001001010110,那么我们在字典树上就应该尽量找到11110110101001这样的遍历序列,如果某一位并不存在这样的节点,那只好有啥走啥,争取在后面的位中尽量取相反的匹配即可。

    这里利用了字典树存储位数相同数节约空间的特点,同时也利用了字典树对大量数据方便查找的特点,既然无法对一个一个数进行n^2的一一比较,那么就把这些数存在字典树上。比较高位就比较了大量一样的数的高位。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int maxn=1e5+10;
    int num[maxn],n;
    int tre[maxn<<4][2];
    int tot;
    void insert(int a,int rt)
    {
        for(int i=31;i>=0;i--)
        {
            int x=(a>>i)&1;
            if(!tre[rt][x])tre[rt][x]=++tot;
            rt=tre[rt][x];
        }
    }
    int finds(int a,int rt)
    {
        int res=0;
        for(int i=31;i>=0;i--)
        {
            int x=(a>>i)&1;
            res<<=1;
            if(tre[rt][!x])rt=tre[rt][!x],res++;
            else rt=tre[rt][x];
        }
        return res;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            tot=0;
            int rt=++tot;
            memset(tre,0,sizeof tre);
            scanf("%d",&n);
            for(int i=0;i<n;i++)
                scanf("%d",&num[i]),insert(num[i],rt);
            int ans=0;
            for(int i=0;i<n;i++)
                ans=max(ans,finds(num[i],rt));
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    【LOJ】 #2015. 「SCOI2016」妖怪
    【LOJ】#2016. 「SCOI2016」美味
    【LOJ】 #2008. 「SCOI2015」小凸想跑步
    【LOJ】#2007. 「SCOI2015」国旗计划
    【LOJ】#2006. 「SCOI2015」小凸玩矩阵
    【LOJ】#2172. 「FJOI2016」所有公共子序列问题
    【LOJ】#2173. 「FJOI2016」建筑师
    【LOJ】#2174. 「FJOI2016」神秘数
    【LOJ】#2280. 「FJOI2017」矩阵填数
    【洛谷】P4585 [FJOI2015]火星商店问题
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135733.html
Copyright © 2011-2022 走看看