zoukankan      html  css  js  c++  java
  • 【BZOJ3668】[NOI2014] 起床困难综合症(位运算思想)

    点此看题面

    大致题意: 给定一些位运算操作,让你在(0sim m)范围内选一个初始值,使其在经过这些运算后得到的结果最大。

    前置技能:关于位运算

    作为一道位运算的题,如果你不知道什么是位运算,那就完全做不了了。

    关于位运算可以详见这篇博客:位运算相关(一)——位运算学习笔记

    接下来,我们还要了解位运算的一个性质:即位运算的各数位之间是互不影响的

    根据这个性质,我们就可以得出一个大致思路了。

    大致思路

    由于位运算时各数位是相互独立的,因此对于各数位,其实只有两种情况:(0)(1)

    则我们可以考虑用两个变量(s1)(s2),初始化分别为(0)(-1)(-1)在二进制下每一位都是(1)),分别表示每一位选(0)和选(1)的情况,来执行完所有操作。

    则此时,对于二进制下的某一位,有三种情况:

    • (s1)中这一位为(1)。说明如果这一位初始值为(0)时最终结果为(1),则自然选这一位为(0)
    • (s1)中这一位为(0),但(s2)中这一位为(1)。说明如果这一位初始值为(1)时最终结果为(0),则判断当前这位是否能选为(1),如果能选,由于二进制数的大小是由高位决定的,因此必选,否则为(0)
    • (s1)(s2)中这一位全为(0)。则说明这一位无论如何最终结果都为(0),则贪心地选其为(0)

    按照这样的套路,就能求出答案了。

    代码

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    #define Gmin(x,y) (x>(y)&&(x=(y))) 
    #define abs(x) ((x)<0?-(x):(x))
    #define swap(x,y) (x^=y^=x^=y)
    #define uint unsigned int
    #define LL long long
    #define ull unsigned long long
    #define INF 1000000000
    using namespace std;
    int n,m,s1=0,s2=-1;//用两个变量s1和s2分别表示每一位选0和选1的情况
    class Class_FIO
    {
        private:
            #define Fsize 100000
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
            #define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
            int f,FoutSize,Top;char ch,Fin[Fsize],*A,*B,Fout[Fsize],Stack[Fsize];
        public:
            Class_FIO() {A=B=Fin;}
            inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));x*=f;}
            inline void reads(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())&&~ch);}
            inline void write(int x) {if(!x) return pc('0');x<0&&(pc('-'),x=-x);while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
            inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
    }F;
    int main()
    {
        register int i,x,ans=0;register string op;
        for(F.read(n),F.read(m),i=1;i<=n;++i) 
        {
            F.reads(op),F.read(x);
            switch(op[0])
            {
                case 'A':s1&=x,s2&=x;break;
                case 'O':s1|=x,s2|=x;break;
                case 'X':s1^=x,s2^=x;break;
            }
        }
        for(i=30;~i;--i) if(s1&(1<<i)) ans+=1<<i;else if(s2&(1<<i)&&(1<<i)<=m) ans+=1<<i,m-=1<<i;//分类讨论求答案
        return F.write(ans),F.clear(),0;
    }
    
  • 相关阅读:
    函数的存储 堆和栈
    函数的容错处理 函数的返回值
    Linux启动故障排查和修复技巧
    干货 | 亿级Web系统负载均衡几种实现方式
    利用expect批量修改Linux服务器密码
    干货 | LVM快照学习
    实战 | Linux根分区扩容
    LVM 逻辑卷学习
    Shell脚本实战:日志关键字监控+自动告警
    手把手教你在Linux中快速检测端口的 3 个小技巧
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3668.html
Copyright © 2011-2022 走看看