【题解】起床困难综合症[位运算][贪心]

题目链接:

https://www.acwing.com/problem/content/description/1000/

ACwing博客:https://www.acwing.com/user/myspace/index/105140/

### 题目描述
NOI传统风格,很多废话,大意其实就是:
给定一个数M,和N组位计算
求在0到M之间的任意数进行这N组运算之后的最大的答案。

### 算法详解
首先知道位运算的一个重要特征:
除了位移以外的每个位运算,**都与其他位无关,只与本位有关**
也就是说,进行相同的位运算,00100 和 11100 两数的后三位结果是一样的
而我们又知道:
**0的二进制是:00000000…………
-1的二进制是:1111111111…………**
所以!就有了一个绝妙的想法!
只用0和-1进行位运算,就可以的到任何一位的任何情况进行位运算的结果
这只需要计算2*n次计算,而且不需要开数组!!
接下来,只需要从大到小枚举每一个位,枚举条件也很简单:
1,如果这个位用1就大于M,那么只好用0;
2,如果这个位用0得到的结果位是1,那么果断用0
3,如果1,2都不满足,且用1得到结果为1,那么用1
4,如果用1还是用0结果都是0,还是用0(给后面留下操作空间,尽量满足条件1)

这么这题的O(n)算法就出炉了!

##### C++实现
```
#include <iostream>
#define LL long long
using namespace std;
char a[3];
LL n,m,op,tr0,tr1,ans;
int main(){
    cin >> n >> m;
    tr0=0;tr1=-1;
    for(int i=0;i<n;i++){
        cin >> a >> op;
        if(a[0]=='A'){
            tr0=tr0&op;
            tr1=tr1&op;
        }else if(a[0]=='O'){
            tr0=tr0|op;
            tr1=tr1|op;
        }else if(a[0]=='X'){
            tr0=tr0^op;
            tr1=tr1^op;
        }
    }
    int p=0;
    for(int i=0;(1<<i)<=m;i++){ p++; }
    ans=((tr0>>p)<<p);
    p--;
    bool bn0=false;
    //扫描一遍
    for(int i=p;i>=0;i--){
        if((tr0>>i)&1){
            ans=ans|(1<<i);
            if((m>>i)&1) bn0=true;
        }else if((tr1>>i)&1){
            if((m>>i)&1 || bn0){
                ans=ans|(1<<i);
            }
        }else if((m>>i)&1) bn0=true;
        
    }
    cout << ans;
    return 0;
}
```
#### 时间复杂度
O(n)线性的复杂度!解完只要几毫秒

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值