把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ3668】[NOI2014] 起床困难综合症(位运算思想)

点此看题面

大致题意: 给定一些位运算操作,让你在\(0\sim 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;
}
posted @ 2018-11-22 18:31  TheLostWeak  阅读(188)  评论(0编辑  收藏  举报