玲珑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 }
原文地址:https://www.cnblogs.com/zzqc/p/7323433.html