zoukankan      html  css  js  c++  java
  • codevs 3031:最富有的人

    题目描述 Description
    在你的面前有n堆金子,你只能取走其中的两堆,且总价值为这两堆金子的xor值,你想成为最富有的人,你就要有所选择。
    
    输入描述 Input Description
    第一行包含两个正整数n,表示有n堆金子。
    第二行包含n个正整数,表示每堆金子的价值。
    
    输出描述 Output Description
    第一行包含一个正整数,表示能获得的最大总价值。
    
    样例输入 Sample Input
    10
    1 2 3 4 5 6 7 8 9 10
    
    样例输出 Sample Output
    15
    
    数据范围及提示 Data Size & Hint
    数据范围:
    n<=100000 每堆金子数<=2^31-1
    题目

      芒果君:这道题第一个难点在,你特么看不出它是trie树啊啊啊啊!

      然后,就算你看出来了,不会位运算,也hin难搞。

      过程描述起来很简单,就是把每个数字变成二进制从位数上限开始建立trie树,再逐个查询,尽量向“1”的方向走取最大更新答案。这里出现的几个位运算我弱弱的解释一下。

      ① (x>>i)&1 的作用是找到二进制下x从右到左的第i+1位,一个数“>>”右移i是除以2的x次方,“&”叫位与,同为1则为1,否则为0,用它可以找到二进制的每一位数,因为1&1=1,0&1=0;

      ② trie[p][t^1]  “^”叫异或,不同为1相同为0,你可以理解为“不进位的加法”,0^0=0,0^1=1,1^1=0,而且我才发现这道题用它找路的奇妙性质。我们的贪心策略是尽量往1走,如果该位是0需要1变成1,1需要0变成1,但是你有木有发现,它需要的“路”其实就是该位的数字与1异或的结果!

      ③total|=(1<<i)  左移“<<”就是乘2的i次方,“|”位或,只要有一个是1就是1,不然是0,它在这里可以强行把那一位改成1;

      

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define maxn 100010
     5 using namespace std;
     6 int trie[maxn<<6][3],cnt,n;
     7 long long a[maxn],ans;
     8 void insert(int x)
     9 {
    10     int p=0;
    11     for(int i=30;i>=0;--i){
    12         int t=(x>>i)&1;
    13         if(!trie[p][t]) p=trie[p][t]=++cnt;
    14         else p=trie[p][t];
    15     }
    16 }
    17 void query(int x)
    18 {
    19     int p=0;
    20     long long sum=0; 
    21     for(int i=30;i>=0;--i){
    22         int t=(x>>i)&1;
    23         if(!trie[p][t^1]) p=trie[p][t];
    24         else{
    25             p=trie[p][t^1];
    26             sum|=(1<<i); 
    27         }
    28     }
    29     ans=max(ans,sum);
    30 }
    31 int main()
    32 {
    33     scanf("%d",&n);
    34     for(int i=1;i<=n;++i){
    35         scanf("%lld",&a[i]);
    36         insert(a[i]);
    37     }
    38     for(int i=1;i<=n;++i) query(a[i]);
    39     printf("%lld
    ",ans);
    40     return 0;
    41 }

      (PS:好久没有这么认真的写过题解了……) 

  • 相关阅读:
    2019 CCSU GOLD!!!
    HDU 3397 Sequence operation(线段树区间染色加区间合并)
    浅谈线段树区间更新里的懒标记
    HDU 3308 LCIS(线段树区间合并)
    51Nod 1593 公园晨跑(RMQ,ST表)
    第四次作业
    lintcode-166-链表倒数第n个节点
    lintcode-163-不同的二叉查找树
    lintcode-162-矩阵归零
    lintcode-161-旋转图像
  • 原文地址:https://www.cnblogs.com/12mango/p/7241294.html
Copyright © 2011-2022 走看看