由于给出的二进制运算的特点是不进位,所以每一位的计算是独立的。由于题目要求我们求出经过 $n$ 次操作后答案最大的 $x$ 并且 $x \in [0,m]$,所以可以从高位到低位分别枚举 $x$ 的每一位上填 $0$ 还是填 $1$。
具体的,$x$ 的第 $i$ 位可以填 $1$ 当且仅当:
1. 填上 $1$ 后 $x <= m$
2. 该位填 $1$ 优于该位填 $0$
首先第一种情况,我们只要判断当前 $x + (1 << i)$ 是否小于 $m$;
第二种情况,我们分别计算填 $1$ 和 填 $0$ 后的答案,比较即可确定该位的填法。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, m, ans;
int t[N], op[N];
int work(int x, int j) {
for (int i = 1; i <= n; i ++) {
if (op[i] == 1) x &= t[i] >> j & 1;
else if (op[i] == 2) x |= t[i] >> j & 1;
else x ^= t[i] >> j & 1;
}
return x;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++) {
char s[10];
scanf("%s %d", s, &t[i]);
if (*s == 'A') op[i] = 1;
else if (*s == 'O') op[i] = 2;
else op[i] = 3;
}
for (int i = 30; i >= 0; i --) {
if (1 << i <= m) {
int x = work(0, i), y = work(1, i);
if (x >= y) ans |= x << i;
else ans |= y << i, m -= 1 << i; // 这里填 1 时直接用m减掉 1 << i,方便判断
} else {
ans |= work(0, i) << i;
}
}
printf("%d\n", ans);
return 0;
}