CF1288D Minimax Problem(二分 + 状态压缩)
思路:我们通过二分去试探答案,假设答案是x,则我们把数组中大于等于key的标记为1,反之标为0。我们知道m = 8,则01串的情况只有2^8-1种,那么我们可以把n行的情况压缩在vis[2^8-1]长度的数组中,vis记录符合的下标,如果(!vis[x] && !vis[y] && (x | y) == (2^8 -1))说明这个key是符合的,我们继续通过二分去试探更大的答案。
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <functional> 5 #include <set> 6 #include <vector> 7 #include <queue> 8 #include <cstring> 9 #include <stack> 10 11 using namespace std; 12 13 #define ll long long 14 #define pb push_back 15 #define fi first 16 #define se second 17 18 vector<vector<int > > a; 19 vector<int > vis; 20 int n, m; 21 int fi, se; 22 23 bool check(int mid){ 24 fill(vis.begin(), vis.end(), 0); 25 for(int i = 1; i <= n; ++i){ 26 27 int cur = 0; 28 for(int j = 1; j <= m; ++j){ 29 if(a[i][j] >= mid) cur |= (1 << (j - 1)); 30 } 31 //cout << "cur = " << cur << endl; 32 vis[cur] = i; 33 } 34 35 for(int i = 0; i < (1 << m); ++i){ 36 for(int j = 0; j < (1 << m); ++j){ 37 if(vis[i] && vis[j] && (i | j) == (1 << m) - 1){ 38 fi = vis[i]; 39 se = vis[j]; 40 return true; 41 } 42 } 43 } 44 return false; 45 } 46 47 void solve(){ 48 cin >> n >> m; 49 a.resize(n + 1, vector<int >(m + 1)); 50 vis.resize((1 << m) + 10); 51 for(int i = 1; i <= n; ++i){ 52 for(int j = 1; j <= m; ++j) 53 cin >> a[i][j]; 54 } 55 int l = 0, r = (int)1e9 + 10; 56 while(l <= r){ 57 int mid = (l + r) >> 1; 58 //cout << mid << endl; 59 if(check(mid)) l = mid + 1; 60 else r = mid - 1; 61 } 62 cout << fi << " " << se << endl; 63 } 64 65 int main(){ 66 67 // freopen("C:\\Users\\admin\\Desktop\\input.txt", "r", stdin); 68 // freopen("C:\\Users\\admin\\Desktop\\output.txt", "w", stdout); 69 ios::sync_with_stdio(false); 70 cin.tie(0); 71 cout.tie(0); 72 solve(); 73 74 return 0; 75 }
1