zoukankan      html  css  js  c++  java
  • 起床困难综合症

    题目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 }
  • 相关阅读:
    Swift入门篇-Hello World
    Swift入门篇-swift简介
    Minecraft 插件 world edit 的cs 命令
    搭建本地MAVEN NEXUS 服务
    MC java 远程调试 plugin 开发
    企业内部从零开始安装docker hadoop 提纲
    javascript 命令方式 测试例子
    ca des key crt scr
    JSF 抽象和实现例子 (函数和属性)
    form 上传 html 代码
  • 原文地址:https://www.cnblogs.com/qqq1112/p/14280657.html
Copyright © 2011-2022 走看看