洛谷 P2114 [NOI2014] 起床困难综合症-普及+/提高
题目描述
212121 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳。作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争。通过研究相关文献,他找到了该病的发病原因:在深邃的太平洋海底中,出现了一条名为 drd 的巨龙,它掌握着睡眠之精髓,能随意延长大家的睡眠时间。正是由于 drd 的活动,起床困难综合症愈演愈烈,以惊人的速度在世界上传播。为了彻底消灭这种病,atm 决定前往海底,消灭这条恶龙。历经千辛万苦,atm 终于来到了 drd 所在的地方,准备与其展开艰苦卓绝的战斗。drd 有着十分特殊的技能,他的防御战线能够使用一定的运算来改变他受到的伤害。具体说来,drd 的防御战线由 nnn 扇防御门组成。每扇防御门包括一个运算 opopop 和一个参数 ttt,其中运算一定是 OR,XOR,AND\text{OR},\text{XOR},\text{AND}OR,XOR,AND 中的一种,参数则一定为非负整数。如果还未通过防御门时攻击力为 xxx,则其通过这扇防御门后攻击力将变为 x op tx~op~tx op t。最终 drd 受到的伤害为对方初始攻击力 xxx 依次经过所有 nnn 扇防御门后转变得到的攻击力。
由于 atm 水平有限,他的初始攻击力只能为 000 到 mmm 之间的一个整数(即他的初始攻击力只能在 0,1,…,m0,1,\ldots,m0,1,…,m 中任选,但在通过防御门之后的攻击力不受 mmm 的限制)。为了节省体力,他希望通过选择合适的初始攻击力使得他的攻击能让 drd 受到最大的伤害,请你帮他计算一下,他的一次攻击最多能使 drd 受到多少伤害。
输入格式
输入文件的第 111 行包含 222 个整数,依次为 n,mn, mn,m,表示 drd 有 nnn 扇防御门,atm 的初始攻击力为 000 到 mmm 之间的整数。
接下来 nnn 行,依次表示每一扇防御门。每行包括一个字符串 opopop 和一个非负整数 ttt,两者由一个空格隔开,且 opopop 在前,ttt 在后,opopop 表示该防御门所对应的操作,ttt 表示对应的参数。
输出格式
输出一行一个整数,表示 atm 的一次攻击最多使 drd 受到多少伤害。
输入输出样例 #1
输入 #1
3 10
AND 5
OR 6
XOR 7
输出 #1
1
说明/提示
【样例说明】
atm 可以选择的初始攻击力为 0,1,…,100,1,\ldots ,100,1,…,10。
假设初始攻击力为 444,最终攻击力经过了如下计算
- 4 AND 5=44 \text{ AND } 5 = 44 AND 5=4;
- 4 OR 6=64 \text{ OR } 6 = 64 OR 6=6;
- 6 XOR 7=16 \text{ XOR } 7 = 16 XOR 7=1。
类似的,我们可以计算出初始攻击力为 1,3,5,7,91,3,5,7,91,3,5,7,9 时最终攻击力为 000,初始攻击力为 0,2,4,6,8,100,2,4,6,8,100,2,4,6,8,10 时最终攻击力为 111,因此atm的一次攻击最多使drd受到的伤害值为 111。
【数据规模与约定】
- 特殊性质 A\mathrm AA:存在一扇防御门为 AND 0\texttt{AND 0}AND 0;
- 特殊性质 B\mathrm BB:所有防御门的操作均相同。
对于所有数据,保证 2≤n≤1052\le n\le 10^52≤n≤105,0≤m≤1090\le m\le 10^90≤m≤109,0≤t≤1090\le t\le 10^90≤t≤109,且 op\mathrm{op}op 一定为 AND,OR,XOR\verb!AND!,\verb!OR!,\verb!XOR!AND,OR,XOR 中的一种。
solution
考虑到每个操作都是位运算,所以只需要计算每一位如果是 0 或者 1 到状态即可,所以可以用全 0 和全 1 参与运算得到两种结果。最后用贪心在不超过 m 的情况下,优先满足低位以获得最大的得分。
代码
#include <iostream>
#include "bit"
#include "vector"
#include "unordered_set"
#include "unordered_map"
#include "set"
#include "queue"
#include "algorithm"
#include "bitset"
#include "cstring"
#include "cmath"using namespace std;const int N = 101;int a[2] = {0, 0x7fffffff};int main() {int n, m, t;string s;cin >> n >> m;for (int i = 0; i < n; i++) {cin >> s >> t;if (s == "AND") {a[0] &= t;a[1] &= t;} else if (s == "OR") {a[0] |= t;a[1] |= t;} else {a[0] ^= t;a[1] ^= t;}}int k = 0, ans = 0;for (int i = 0; i < 30; i++) {if (a[0] & (1 << i)) ans += 1 << i;else if (a[1] & (1 << i) && k + (1 << i) <= m) {ans += 1 << i;k += (1 << i);}}cout << ans;return 0;
}