Loading

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\n", 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\n", ans);
39     }
40     return 0;
41 }

 

posted @ 2017-04-13 01:12  Shadowdsp  阅读(466)  评论(0编辑  收藏  举报