codeforces 1288D. Minimax Problem(二分)

链接:https://codeforces.com/contest/1288/problem/D

D. Minimax Problem

题意:给定n个数组,长度为m,从n中数组挑选两个数组,两个数组中的每一位取两者的最大值组成一个新的数组,新数组中的最小值记为c,所有组合中c的最大值

思路:题目中m的范围只有8,数组中元素的范围是1e9,显然m的范围非常特殊,似乎可以把数组用二进制的形式进行状态压缩,这里采用二分答案的方法。二分范围是数组元素最小值到最大值,每次check(mid)一遍,check的时候对于每个数组,用二进制的形式表示出来,数组中小于mid的值用0表示,大于等于mid的用1表示,此时所有的数组都进行了二进制转化,比如一个数组1 2 3 4 5,mid = 3,然后数组就可以状态压缩为0 0 1 1 1  。然后去枚举这些二进制,这样其实最多只会枚举2m × 2m 次,如果枚举的两组二进制相或为11111111,那么说明找到了一组解,返回继续二分,如此过程时间复杂度只有O(n×m + 2m×2m),m的范围只有8。具体看代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<queue> 
 7 using namespace std;
 8 typedef long long ll;
 9 const int maxn = 3e5+5;
10 int n,m;
11 int cnt[maxn];
12 int a[maxn][10];
13 int num[270];
14 int ans1,ans2;
15 bool check(int cur){
16     memset(num,0,sizeof(num));//初始化num数组 
17     for(int i = 1;i<=n;i++){
18         int x = 0;
19         for(int j = m - 1;j>=0;j--){
20             if(a[i][j]>=cur) x+=(1<<j);///统计满足a[i][j]>=cur的数组的每一位 
21         }
22         num[x] = i;//每个数组都转化为二进制
23     }
24     for(int i = 0;i<(1<<m);i++){
25         for(int j = 0;j<(1<<m);j++){
26             if(num[i]!=0 && num[j]!=0 && (j|i) == (1<<m)-1){//枚举二进制形式的所有数
27                 ans1 = num[i];
28                 ans2 = num[j];
29                 return true;
30             }
31         }
32     }
33     return false;
34 }
35 int main(){
36     int r = -1,l = 1e9+10;
37     scanf("%d%d",&n,&m);
38     for(int i = 1;i<=n;i++){
39         for(int j = 0;j<m;j++){
40             scanf("%d",&a[i][j]);
41             r = max(r,a[i][j]);
42             l = min(l,a[i][j]);
43         }
44     }
45     int mid;
46     while(l<r){//二分答案 
47         mid = (l+r+1)/2;
48         if(check(mid)) l = mid ;
49         else r = mid - 1;
50     }
51     check(l);
52     printf("%d %d",ans1,ans2);
53     return 0;
54 }

猜你喜欢

转载自www.cnblogs.com/AaronChang/p/12210870.html