Luogu P2114 起床困难综合症
Luogu P2114 起床困难综合症
由于这道题的三个操作都是位运算,即每一位的贡献都是独立的。所以我们可以按位考虑,即考虑初始攻击力和最后伤害的每一位分别是 $0$ 还是 $1$。
因此我们可以先算出每一位分别取 $0$ 和取 $1$ 在经过所有防御门后最后得到的是什么,然后从高位向低位贪心即可。
需要注意的是(也是被卡了很久 $60$ 分的原因),最后得到的攻击力可能远大于 $m$,其上限应当为 $2 ^ {31} - 1$(因为 $10 ^ {9}$ 对应的二进制有 $30$ 位),因此我们循环的范围不应由 $m$ 的二进制位数确定。
时间复杂度为 $\text{O} (kn)$($k$ 即为攻击力可能的最大位数,本题中为 $30$)。
#include <bits/stdc++.h>
#define N 100010
int n, m;
int op[N], t[N], f[32][2];
long long ans;
namespace WalkerV {
void Read() {
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
char tmp[5];
getchar();
scanf ("%s %d", tmp, &t[i]);
switch (tmp[0]) { //or - 1, xor - 2, and - 3
case 'O':
op[i] = 1;
break;
case 'X':
op[i] = 2;
break;
case 'A':
op[i] = 3;
break;
}
}
return;
}
void Solve() {
for (int k = 0; k <= 30; k++) {
int val = 0;
for (int i = 0; i <= 1; i++) {
int tmp = i;
for (int j = 0; j < n; j++) {
switch (op[j]) {
case 1:
tmp |= ((t[j] >> k) & 1);
break;
case 2:
tmp ^= ((t[j] >> k) & 1);
break;
case 3:
tmp &= ((t[j] >> k) & 1);
break;
}
}
f[k][i] = tmp;
}
}
long long tmp = 0;
for (int i = 30; i >= 0; i--) {
if ((f[i][0] < f[i][1]) && (tmp + (1 << i) <= m)) {
tmp += (1 << i), ans += (f[i][1] << i);
}
else {
tmp += (0 << i), ans += (f[i][0] << i);
}
}
return;
}
void Print() {
printf("%lld\n", ans);
return;
}
}
int main()
{
WalkerV::Read();
WalkerV::Solve();
WalkerV::Print();
return 0;
}