《算法竞赛进阶指南》-AcWing-998. 起床困难综合症-题解

114 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

@TOC

起床困难综合症

传送门

题目描述

为了打败起床困难综合症去打败睡眠boss,boss有nn扇防御门,每扇门包含一个运算符(ORXORANDOR、XOR、AND)和一个运算数(非负整数),攻击经过这扇门后将与门进行相应的运算操作。

勇士的初始攻击力只能是[0,m][0,m]之间的一个整数,门及其摆放是固定的,勇士想通过合适的攻击以对boss照成最大的伤害。

输入样例

3 10
AND 5
OR 6
XOR 7

解释:一共33扇门,初始攻击在00~1010之间,第一扇门将与攻击和5进行与运算,第二扇将第一扇运算后的结果与6进行或操作,最后一扇门将前面的结果与7进行异或。

样例输出

1

解释:假设初始攻击力为4(0410)4(0\leq4\leq10),则经过如下运算:

4 AND 5 = 4
4 OR 6 = 6
6 XOR 7 = 1

获得最终攻击力为1。在00~1010中找不到另外一个数使得最终运算的结果大于11

解题思路

攻击力的每一位与另一位互不影响。10910^9的数据不超过3030位。

我们只需要分别看每一位(0和1两种情况),如果这一位是11通过所有门后将会变成什么、如果是00又会变成什么。

  • 当然,我们希望最终攻击尽可能大,这就需要我们先从高位开始计算;
  • 我们希望初始攻击尽可能小(需要不超过mm),这就需要满足以下两个条件时才让这一位的初始攻击力为11
    • 这一位初始为11的最终攻击力大于初始为00的最终攻击力
    • 这一位初始为11的话目前初始攻击力不超过最大攻击力mm

更多解释请见代码注释


AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
string op[100010];
int num[100010];
int n;
int calculate(int wei, int thisBit) // 计算初始攻击的第wei位初始值位thisBit时,通过所有门后的最终攻击力
{
    for(int i=0;i<n;i++) // 每扇门
    {
        int thisBit2=num[i]>>wei&1; // 取出这扇门的操作数的这一位
        if(op[i]=="AND")thisBit&=thisBit2; // 如果这扇门的AND,就做与运算
        else if(op[i]=="OR")thisBit|=thisBit2; // OR就做或运算
        else thisBit^=thisBit2; // 否则异或运算
    }
    return thisBit; // 返回这一位经过所有门后最终的值
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int m;
    cin>>n>>m;
    for(int i=0;i<n;i++)
        cin>>op[i]>>num[i];
    int ans=0, original=0;
    for(int i=29;i>=0;i--) // 从大到小分析每一位
    {
        int one=calculate(i, 1); // 如果这一位的初始攻击力是1,最终攻击力将会是one
        int zero=calculate(i, 0); // 如果这一位的初始攻击力是0,最终攻击力将会是zero
        if(original+(1<<i)<=m&&one>zero) // 如果这一位为1的话初始攻击力<=m 并且 这一位为1的话最终攻击力大于这一位为0的话的最终的攻击力
            original+=1<<i, ans+=one<<i; // 那么这一位初始攻击力设为1,初始攻击力加上这一位,最终攻击力加上这一位为1的时候产生的最终攻击力one
        else
            ans+=zero<<i; // 否则这一位初始攻击力为0,最终攻击力加上这一位初始值为0的时候产生的最终的攻击力zero
    }
    cout<<ans<<endl; // 输出答案
    return 0;
}

同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:letmefly.blog.csdn.net/article/det…