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 }
  • 相关阅读:
    关于 MySQL int tinyint 类型的那点事
    PHP日期、时间戳相关的小程序
    [leedcode 236] Lowest Common Ancestor of a Binary Tree
    [leedcode 235] Lowest Common Ancestor of a Binary Search Tree
    [leedcode 234] Palindrome Linked List
    [leedcode 233] Number of Digit One
    [leedcode 232] Implement Queue using Stacks
    [leedcode 231] Power of Two
    [leedcode 230] Kth Smallest Element in a BST
    [leedcode 229] Majority Element II
  • 原文地址:https://www.cnblogs.com/qqq1112/p/14280657.html
Copyright © 2011-2022 走看看