原题链接: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; }