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 }