P2114 [NOI2014]起床困难综合症

题目地址

经典状态压缩题,思路挺巧妙的。(也可能是我太蒻了吧)、、、

题解

我们要从 \([0-m]\) 中间选一个数 \(x_0\) 使得最后的攻击力最大。

如果从二进制的角度来观察 \(x_0\) ,你就会发现一系列的 \(\text{xor}\)\(&\)\(|\) 操作只不过是 \(x_0\) 二进制下的每一位在进行这一系列操作,使得最后的答案最大。

“换言之,对于任意的 k(0<=k<=30),‘ans 的第 k 位是几’只与‘ \(x_0\) 的第 k 位是几’有关”

于是考虑二进制下填位的方法,从高位到低位依次填 \(1\)\(0\)

\(x_0\)\(k\) 位上填 1 ,当且仅当

  • \(x_0\)\(k\) 位上填 1 ,值不会超过 \(m\)

  • \(x_0\)\(k\) 位上填 1 比填 0 要优

知道什么时候太填 \(1\) 什么时候填 \(0\),你就可以轻轻松松切掉这道题了。

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
int n,m;
int t[N];
string op[N];
inline int calc(int k,int now) {
    for(int i=1;i<=n;++i) {
        int x = (t[i]>>k) & 1;
        if(op[i] == "AND") now &= x;
        else if(op[i] == "OR") now |= x;
        else now ^= x;
    }
    return now;
}   //运算n次后看返回 1 还是 0 
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) {
        char str[5];
        scanf("%s%d",str,&t[i]); op[i] = str;
    }
    int val = 0 ,ans = 0;   //ans来保存最后攻击力 
    for(int i=29;i>=0;--i) {    //位运算学着学着就从零开始计数了qwq 
        int res0 = calc(i,0) ,res1 = calc(i,1); //分别处理看一下填0和填一会怎么样
        if(val+(1<<i)<=m && res0<res1)
            val += (1<<i) ,ans += (res1<<i);
        else
            ans += (res0<<i);
    }
    printf("%d\n",ans);
    return 0;
}

刚刚看了一下洛谷题解,发现题解的大佬们都吊打我,还说这是一道大水题。

转载于:https://www.cnblogs.com/BaseAI/p/11407233.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值