起床困难综合症

题目link:https://www.luogu.com.cn/problem/P2114

首先考虑暴力:直接枚举 $0$ ~ $m$ ,即初始攻击力,然后计算出其通过每扇门后的值, $ans$ 记录最大值即可。时间复杂度 $O(n$ $*$ $m)$ 。

考虑优化:首先可以知道 & (与) 、| (或)、^  (异或) 三个操作对于二进制来说是按位独立的,即它们对二进制的每一位是可以分别进行操作的。所以可以直接枚举二进制上的每一位数( $1$ 或 $0$ ),然后将这个数放入门里进行计算,最后的答案就是这些数字连在一起组成的二进制。

考虑实现:首先对于一个二进制数来说,要想它的值最大,那么和十进制数一样的,也是最高位越大越大,满足贪心。因此在枚举二进制上的每一位数时,需要判断是 $1$ 放入门里得出的是 $1$ ,还是 $0$ 放入门里是 $1$。根据贪心,肯定选择从门中出来为 $1$ 的更好。但是还需要考虑的一件事是当前枚举的二进制位数不能大于 $m$,所以有时只能选择 $0$ ,但是当其中有一位 $m$ 为 $1$,而选择为 $0$ ,那么之后不管是选 $1$ 还是 $0$ ,这个二进制的值永远不会比 $m$ 大,就可以任取了。但是注意一点,这个枚举二进制的位数是不一定等于 $m$ 的,因为大于 $m$ 的那些位都可以视为 $0$ ,但万一这些 $0$ 进门之后变成了 $1$ 那结果不就更优了吗?

考虑选 $1$ 更优,还是 $0$ 更优(假设此时能选 $1$,否则只能选 $0$):

  • 选 $1$ 为 $1$ ,选 $0$ 为 $1$ :此时选两种情况都符合贪心,但是,选 $0$ 的话后面不管 $1$ 还是 $0$ 都可以选,因此此时选 $0$。
  • 选 $1$ 为 $0$ ,选 $0$ 为 $0$ :此时选两种情况都一样,但是和上一种情况一样的,选 $0$ 。
  • 选 $1$ 为 $1$ ,选 $0$ 为 $0$ :此时根据贪心,选 $1$ 。
  • 选 $1$ 为 $0$ ,先 $0$ 为 $1$ :此时根据贪心,选 $0$ 。

实现方法:预处理出 $m$ 的二进制,枚举 $30$ ~ $0$ (注意是从高位到低位),将 $1$ 和 $0$ 放入门里,看哪个更优(判断方法见上),最后再将每一位的二进制数拼接起来即为 $ans$ 。时间复杂度 $O(n$ $*$ $30)$ 。

考虑进一步优化:对于每次将选择的 $1$ 或 $0$ 放入门里,可以考虑预处理,用一个二进制 $x$ 来表示 $31$ 位全是 $1$ 的一个数,和一个二进制 $y$ 来表示 $31$ 位全是 $0$ 的一个数,带入门里进行预处理,之后枚举二进制的时候就不用放进门里了。时间复杂度 $O(n)$ 。

最终优化代码:

 1 #include <bits/stdc++.h>
 2 #define INF 0x3f3f3f3f
 3 using namespace std;
 4 struct Str {char s[10]; int x;}stu[100010];
 5 int n, m, a[35], cnt, jud, ans, x, y;
 6 void change()
 7 {
 8     for(; m; m >>= 1) a[cnt++] = m % 2;
 9     return;
10 }
11 int main()
12 {
13     scanf("%d %d", &n, &m);
14     for(int i = 1; i <= n; ++i)
15         scanf("%s %d", stu[i].s + 1, &stu[i].x);
16     change(); x = (1 << 31) - 1, y = 0;
17     for(int i = 1; i <= n; ++i)
18     {
19         if(stu[i].s[1] == 'A') x &= stu[i].x, y &= stu[i].x;
20         if(stu[i].s[1] == 'O') x |= stu[i].x, y |= stu[i].x;
21         if(stu[i].s[1] == 'X') x ^= stu[i].x, y ^= stu[i].x;
22     }
23     for(int i = 30; i >= 0; --i)
24     {
25         if(a[i] == 0 && !jud) ans |= (y & (1 << i));
26         else if((x & (1 << i)) && (y & (1 << i)) == 0) ans |= (1 << i);
27         else ans |= (y & (1 << i)), jud = 1;
28     }
29     printf("%d", ans);
30     return 0;
31 }

 

posted @ 2021-01-15 10:01  louis_11  阅读(103)  评论(0编辑  收藏  举报