[NOI2014]起床困难综合症

传送门

这道题的思路还是蛮值得学习的。

我们知道,位运算中每一位的运算都是独立的,如果想使得最后的值最大,越多位上是1越好,且所在位越高越好。

因为已经知道初始值的范围,那么我们就可以用每一位全0和每一位全1预先处理出经过所有操作的每一位上的数。

如果某一位上初始为1最后为1,那么这一位上初始值就应该为1

如果某一位上初始为0最后为1,那么这一位上初始值就应该为0

如果某一位上初始为1或0最后都为1,我们优先选0,选小一点,使得更可能在[0,m]的范围内,为后面的选择留有余地。

#include<bits/stdc++.h>
#define N 100003
using namespace std;
int n,m;
int op[N],num[N];
int count(int x)
{
    for(int i=1;i<=n;++i)
    {
        if(op[i]==1) x=x&num[i];
        if(op[i]==2) x=x|num[i];
        if(op[i]==3) x=x^num[i];
    }
    return x;
}
char s[5];
int main()
{
    n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        int x;
        scanf("%s",s);
        scanf("%d",&x);
        num[i]=x;
        if(s[0]=='A')op[i]=1;
        if(s[0]=='O')op[i]=2;
        if(s[0]=='X')op[i]=3;
    }
    int zero=count(0);
    int one=0,tot=0;
    while(one<=m)
    {
        tot++;
        one=one*2;
        one=one+1;
    }
    one=count(one);
    int ans=0;
    for(int i=tot-1;i>=0;--i)//一位位处理 
    {
        if(!(zero&(1<<i))&&(one&(1<<i))&&(ans|(1<<i))<=m)//注意不要超出范围 
        ans|=(1<<i);
    }
    printf("%d
",count(ans));
} 
View Code
原文地址:https://www.cnblogs.com/yyys-/p/11225961.html