BZOJ3668 起床困难综合症¶
题解¶
是非常简单的一道题 然鹅我太弱了还WA了两次 ,只要明白二进制和基本的贪心就行了。
首先对于某个位 i ,先预处理出这一位原来在攻击力中取 0/1 时经过 n 扇门后分别变成 0/1 ,记作 trans[i][0/1]
我们知道对于某一位 j 肯定有 (1 << j) > \sum_{k=0}^{j - 1} (1 << k) ,那么就可以考虑用贪心取最优解。
从大到小位的贪心,如果当前确定的初始攻击力与 M 的差能够使第 i 位填上 1 并且该位填上 1 比填 0 严格优秀,那么就贪心的填 1 并将初始攻击力更新,否则直接填 0,根据所选的数字用 trans[i][0/1] 更新答案。
程序¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | #include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #define MAX_N 100007 typedef long long ll; int N; ll M, x[MAX_N], res; int to[37][2], op[MAX_N]; int main () { scanf("%d%lld", &N, &M); char s[10]; for (int i = 1;i <= N; ++i) scanf("%s%lld", s, x + i), op[i] = (s[0] == 'A' ? 1 : (s[0] == 'O' ? 2 : 3)); for (int i = 0;i <= 30; ++i) to[i][1] = 1; for (int i = 1;i <= N; ++i) { for (int j = 0;j <= 30; ++j) { if (op[i] == 1) { to[j][0] = (to[j][0] & ((x[i] >> j) & 1)); to[j][1] = (to[j][1] & ((x[i] >> j) & 1)); } else if (op[i] == 2) { to[j][0] = (to[j][0] | ((x[i] >> j) & 1)); to[j][1] = (to[j][1] | ((x[i] >> j) & 1)); } else if (op[i] == 3) { to[j][0] = (to[j][0] ^ ((x[i] >> j) & 1)); to[j][1] = (to[j][1] ^ ((x[i] >> j) & 1)); } } } ll sum = 0; for (int i = 30;i >= 0; --i) { if (sum + (1 << i) <= M && to[i][1] > to[i][0]) { sum += (1 << i); if (to[i][1]) res += (1 << i); } else { if (to[i][0]) res += (1 << i); } } printf("%lld\n", res); return 0; } |