[NOI2014]起床困难综合症

原题链接:https://www.luogu.org/problemnew/show/P2114

NOI的水题

题意简述:给出n个指令,在0到m之中选出一个数,使其执行这n个指令后值最大。

一共有三种指令:“和”“或”“异或”,而一个数在二进制下执行三种指令时,各位之间是不能互相影响的。

有一个简单的结论,在二进制中,第x位为1,之后的y位全为0,大于第x位为0,之后y位全为1(“之后”指低位)

非常简单的一个结论,想不明白的请去复习等比数列求和。

将m转化为二进制,从高到低枚举初始数字二进制表示的每一位,有0和1两种选法,会出现如下几种情况:

之前选择的每一位均与m相同,且m中这一位为0:答案中这一位也为0

之前选择的每一位均与m相同,且m中这一位为1:选0或是选1均可,优先选择能使结果中这一位为1的。如果选择0或1均可,选择0

之前选择的与m不同,则答案中这一位选0和1均可,同样优先选择能使结果中这一位为1的

#include<cstdio>
using namespace std;
int n,m,x,l;
int c[35],ans[35],num[35][3];
char s[5];
long long sum;
int main()
{
//    freopen("testdata.in","r",stdin);
    scanf("%d %d",&n,&m);
    for(int i=0;i<33;i++)
    {
        num[i][0]=0;
        num[i][1]=1;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%s %d",s,&x);
        l=-1;
        for(int j=0;j<33;j++) c[j]=0;
        while(x)
        {
            c[++l]=x%2;
            x>>=1;
        }
        for(int j=0;j<33;j++)
        {
            if(s[0]=='A')
            {
                num[j][0]=num[j][0]&c[j];
                num[j][1]=num[j][1]&c[j];
            }
            if(s[0]=='O')
            {
                num[j][0]=num[j][0]|c[j];
                num[j][1]=num[j][1]|c[j];
            }
            if(s[0]=='X')
            {
                num[j][0]=num[j][0]^c[j];
                num[j][1]=num[j][1]^c[j];
            }
        }    
    }
    l=-1;
    for(int i=0;i<33;i++) c[i]=0;
    while(m)
    {
        c[++l]=m%2;
        m>>=1;
    }
    for(int i=32;i>=0;i--)
    {
        ans[i]=0;
        if(c[i]==0) ans[i]=num[i][0];
        else if(c[i]==1)
        {
            if(num[i][0]==1)
            {
                ans[i]=1;
                for(int j=i-1;j>=0;j--) c[j]=1;
            }
            if(num[i][1]==1) ans[i]=1;
            if(num[i][0]==0&&num[i][1]==0)
            {
                for(int j=i-1;j>=0;j--) c[j]=1;
            }
        }
    }
    for(int i=0;i<=32;i++) sum+=(ans[i]<<i);
    printf("%lld",sum);
    return 0;
}
原文地址:https://www.cnblogs.com/zeroform/p/8372223.html