[NOI2014]起床困难综合症
这道题的思路还是蛮值得学习的。
我们知道,位运算中每一位的运算都是独立的,如果想使得最后的值最大,越多位上是1越好,且所在位越高越好。
因为已经知道初始值的范围,那么我们就可以用每一位全0和每一位全1预先处理出经过所有操作的每一位上的数。
如果某一位上初始为1最后为1,那么这一位上初始值就应该为1
如果某一位上初始为0最后为1,那么这一位上初始值就应该为0
如果某一位上初始为1或0最后都为1,我们优先选0,选小一点,使得更可能在[0,m]的范围内,为后面的选择留有余地。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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\n",count(ans)); }