• HihoCoder 1496:寻找最大值(思维DP)


    http://hihocoder.com/problemset/problem/1496

    题意:中文。

    思路:一开始做有一种想法,把所有的数都变成二进制后,最优的情况肯定是挑选所有数中最高位的1能同时有一个以上的数。

    例如样例2可以化成:

    001

    010

    100

    101

    那么肯定挑选最高位的1(第三位)并且有一个以上的数更优,如果没有一个以上那么与之后会变成0.

    那么对于这一位应该如何挑选。

    一开始想着只挑选最大的两个,但是造出下面的样例:

    1001000

    1000110

    1000110

    这样的样例显然是挑选下面的两个更优。

    于是YY出了一种想法,直接往前面扫,对于每一位的1只挑选最大的两个,然后更新答案,最后居然对了。(肯定是数据太水了)。

    A了之后想知道为什么,大概和这个有点像吧http://blog.csdn.net/ddjing_/article/details/69072023。。。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define N 101000
     4 typedef long long LL;
     5 int num[N];
     6 LL bit[21][2];
     7 
     8 int main() {
     9     int t; scanf("%d", &t);
    10     while(t--) {
    11         memset(bit, 0, sizeof(bit));
    12         int n; scanf("%d", &n);
    13         for(int i = 1; i <= n; i++) scanf("%d", &num[i]);
    14         for(int i = 1; i <= n; i++) {
    15             int tmp = num[i], cnt = 0;
    16             while(tmp) {
    17                 if(tmp & 1) {
    18                     if(bit[cnt][0] < num[i]) bit[cnt][1] = bit[cnt][0], bit[cnt][0] = num[i];
    19                     else if(bit[cnt][1] < num[i]) bit[cnt][1] = num[i];
    20                 }
    21                 cnt++; tmp >>= 1;
    22             }
    23         }
    24         LL ans = 0;
    25         for(int i = 20; i >= 0; i--) {
    26             LL now = bit[i][0] * bit[i][1] * (bit[i][0] & bit[i][1]);
    27             if(ans < now) ans = now;
    28         }
    29         printf("%lld
    ", ans);
    30     }
    31     return 0;
    32 }

    看了下别人的正解:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 #define N 100010
     5 /* 高维前缀最大次大值
     6   我们可以枚举x&y的结果z,找出两个数x&y==z使得x*y最大,更新答案即可,
     7   条件可以被削弱为z为x&y的子集,这种条件放缩不会导致最优解的丢失,
     8   z为x&y的子集等价于z为x的子集并且z为y的子集。
     9   那么我们只要找出以z为子集的最大值和次大值,然后枚举z即可计算出答案。
    10   复杂度O(k*2^k).
    11 */
    12 
    13 struct node {
    14     LL val[2];
    15     node operator + (const node &rhs) const {
    16         LL _val[2] = {val[0], val[1]};
    17         for(int i = 0; i < 2; i++)
    18             if(rhs.val[i] > _val[0]) _val[1] = _val[0], _val[0] = rhs.val[i];
    19             else if(rhs.val[i] > _val[1]) _val[1] = rhs.val[i];
    20         return (node){ _val[0], _val[1] };
    21     }
    22 } dp[(1<<20)+10];
    23 
    24 int main() {
    25     int t; scanf("%d", &t);
    26     int statu = 1 << 20;
    27     while(t--) {
    28         for(int i = 0; i < statu; i++) dp[i] = (node){0, 0};
    29         int n, a; scanf("%d", &n);
    30         for(int i = 1; i <= n; i++) scanf("%d", &a), dp[a] = dp[a] + (node){ a, 0 };
    31         for(int i = 0; i < 20; i++)
    32             for(int j = 0; j < statu; j++)
    33                 if((1 << i) & (~j)) dp[j] = dp[j] + dp[(1 << i) | j]; // 递推子集
    34                 // (1<<i) & (~j) 表示状态j没有(1<<i)这个状态的时候就更新
    35         LL ans = 0;
    36         for(int i = 0; i < statu; i++)
    37             ans = max(ans, dp[i].val[0] * dp[i].val[1] * (dp[i].val[0] & dp[i].val[1]));
    38         printf("%lld
    ", ans);
    39     }
    40     return 0;
    41 }
  • 相关阅读:
    noip模拟赛 花
    noip模拟赛 柜(暴力)
    noip模拟赛 读
    Java基础知识强化47:StringBuffer类之StringBuffer的三个面试题
    Java基础知识强化46:StringBuffer类之判断一个字符串是否对称案例
    Java基础知识强化45:StringBuffer类之字符串反转的案例
    Java基础知识强化44:StringBuffer类之把数组拼接成指定格式的字符串的案例
    Java基础知识强化43:StringBuffer类之StringBuffer和String的相互转化
    Java基础知识强化42:StringBuffer类之StringBuffer的截取功能
    Java基础知识强化41:StringBuffer类之StringBuffer的反转功能
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6702125.html
Copyright © 2020-2023  润新知