p2114 起床困难综合症

传送门

分析

orz zwj

最好想到的方法是我们枚举每一位是0还是1,然后暴力求出经过n个操作之后的结果来决定这一位是0还是1

然后我们发现这种暴力的做法居然能a

但是还有更好的方法

我们只考虑开始的数每位都是0和每位都是1这两种情况

然后算出n次操作之后变成了什么

如果由0变1则我们这一位肯定是0

否则如果由1变1我们就将这一位设为1

其它无法变成1的位全部赋为0即可

详见代码

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int n,m;
int opt[100100],sum[100100],is[100100],Ans;
//opt = 1 OR
//opt = 2 XOR
//opt = 3 AND
inline int have(int x,int wh){
    if(opt[wh]==1)return x|sum[wh];
      else if(opt[wh]==2)return x^sum[wh];
      else return x&sum[wh];
}
inline void deal(int x){
    int i,j,k=(x==0?0:1);
    for(i=1;i<=n;i++)x=have(x,i);
    for(i=30;i>=0;i--)
      if(x&(1<<i)&&!is[i]&&(m>=(1<<i)||!k)){
          Ans+=(1<<i);
          is[i]=1;
          if(k)m-=(1<<i);
      }
    return;
}
int main(){
    int i,j,k;
    scanf("%d%d",&n,&m);
    char s[50];
    for(i=1;i<=n;i++){
      scanf("%s",s);
      if(s[0]=='O')opt[i]=1;
        else if(s[0]=='X')opt[i]=2;
        else opt[i]=3;
      scanf("%d",&sum[i]);
    }
    deal(0);
    deal(-1);
    printf("%d\n",Ans);
    return 0;
}
posted @ 2018-10-31 11:17  水题收割者  阅读(188)  评论(0编辑  收藏  举报