• 玲珑oj 1028 贪心


    http://www.ifrog.cc/acm/problem/1028

    很有趣的一道题,求从n个数里挑出不同的两个,使得他俩'|','&','^'后的值尽量大,求这个最大的结果。

    求最大的异或值想到了trie树的一个经典操作,对于按位与,要两个位置都是1才会出现1,我们肯定要贪心操作,优先使高位为1,

    这也可以在trie上完成,如果这个位置1的个数>=2,至少有两个以这个前缀开头的数字,我们就认为这个位置可以为1,再往下走考虑下一位,

    如果1的个数不满足得话,说明这一位肯定是0了,此时要进行一步合并操作,将0下面的部分合并到1上,因为此位不必要是1所以0/1都可以。

    对于'|',有点复杂我感觉,我们考虑遍历每个数字,是1得位我们就不必管了,然后从最高位的0开始看看是否能变为1.

    例如,对于1000(2),我们首先找有没有x100(2),如果有再找x110(2),高位如果找不到了就找低位,最后得到的就是最大值,

    我们预处理出每个数能拆出来的数,1001->1000,0001,1001。。。依次类推,用一个标记数组。

    之后循环每一个数的时候,记录由高位到低位'0'出现的位置,之后贪心高位找到最大的,只要标记过这个数就表示可以进行或操作。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 int num[35],a[100005];
      4 int ch[2100005][2],cnt[2100005],sz;
      5 void irt(int x)
      6 {
      7     int p=0;
      8     for(int i=20;i>=0;--i){
      9         int bit=(x&(1<<i))?1:0;
     10         if(ch[p][bit]==-1)
     11         {
     12             ch[sz][0]=ch[sz][1]=-1;
     13             cnt[sz]=0;
     14             ch[p][bit]=sz++;
     15         }//cout<<p<<endl;
     16         p=ch[p][bit];
     17         cnt[p]++;
     18     }
     19 }
     20 void uno(int &x,int y)
     21 {
     22     if(y==-1) return;
     23     if(x==-1) {ch[sz][0]=ch[sz][1]=-1;cnt[sz]=0;x=sz++;}
     24     cnt[x]+=cnt[y];
     25     uno(ch[x][0],ch[y][0]);
     26     uno(ch[x][1],ch[y][1]);
     27 }
     28 int solve1(int n)
     29 {
     30     int p=0,ret=0;
     31     for(int i=20;i>=0;--i){
     32         if(ch[p][1]!=-1&&cnt[ch[p][1]]>=2)
     33             ret|=(1<<i);
     34         else uno(ch[p][1],ch[p][0]);
     35     p=ch[p][1];
     36     }
     37     return ret;
     38 }
     39 
     40 int solve2(int x)
     41 {
     42     int ret=0,p=0;
     43     for(int i=20;i>=0;--i){
     44         int bit=(x&(1<<i))?1:0;
     45             if(ch[p][bit^1]!=-1) {p=ch[p][bit^1];ret|=(1<<i);}
     46             else p=ch[p][bit];
     47         if(p==-1) break;
     48     }
     49     return ret;
     50 }
     51 bool dp[(1<<22)];
     52 int solve3(int n)
     53 {
     54     int i,j,ret=0;
     55     memset(dp,0,sizeof(dp));
     56     for(i=1;i<=n;++i) dp[a[i]]=1;
     57     for(i=(1<<20);i>=0;--i)
     58     {
     59         for(j=20;j>=0;--j)
     60         {
     61             if(!(i&(1<<j))) dp[i]|=dp[i|(1<<j)];
     62         }
     63     }
     64     int t[100],p=0;
     65     for(i=1;i<=n;++i)
     66     {
     67         p=0;
     68         for(j=20;j>=0;--j)
     69             if(!(a[i]&(1<<j))) t[p++]=(1<<j);
     70         int x=0;
     71         for(j=0;j<p;++j)
     72         {
     73             if(dp[x|t[j]]) x|=t[j];
     74         }
     75         ret=max(ret,x|a[i]);
     76     }
     77     return ret;
     78 }
     79 int main()
     80 {
     81     int i,j,k,n,m,t,op;
     82 
     83    // freopen("in.txt","r",stdin);
     84      cin>>t;
     85     for(int cas=1;cas<=t;++cas)
     86     {
     87         sz=0;
     88         int xo=0;
     89         cin>>n>>op;
     90         memset(num,0,sizeof(num));
     91         ch[sz][0]=ch[sz++][1]=-1;cnt[0]=0;
     92         for(i=1;i<=n;++i)
     93         {
     94             scanf("%d",a+i);
     95             if(op==2) xo=max(xo,solve2(a[i]));
     96             irt(a[i]);
     97         }
     98         printf("Case #%d: ",cas);
     99         switch(op){
    100         case 1:cout<<solve1(n)<<endl;break;
    101         case 2:cout<<xo<<endl;break;
    102         case 3:cout<<solve3(n)<<endl;break;
    103         }
    104     }
    105     return 0;
    106 }
  • 相关阅读:
    【android】手机增加一个新的实体按键
    python自动化错误解决方法
    java.lang.IllegalArgumentException: Buffer size too small. size = 262144 needed = 2205991
    50个开发工具
    mysql 查询json串
    软考题目单选题目
    软考操作系统基础知识
    使用DM将mysql具体表同步到tidb
    python日期处理
    安装部署dm
  • 原文地址:https://www.cnblogs.com/zzqc/p/7323433.html
Copyright © 2020-2023  润新知