Description
Solution
看到要求 最小值的最大值,显然要想到 二分。
观察到 $m \le 8$,是不是可以 二进制压位 呢?答案是肯定的。
比如我们在判断答案为 $mid$ 是否可行时,我们对每一行定义一个二进制数 $b_i$,这个其实是一个 bitset ,但因为位数太少直接 int 就能实现,当 $a_{i,j} \ge mid$ 时,$b_i$ 的左数第 $j$ 位就是 $1$,否则为 $0$。例如,$mid = 3$,$a_i = \{ 3, 4, 1, 2 \}$,那么 $b_i = 1100_{(2)}$。这时,我们将 $t_{b_{i}} \gets i$,表示此状态的来源。
考虑枚举两个状态 $i, j$,如果 $i, j$ 状态都存在(可以通过先将 $t$ 初始化为 $0$,看 $t_i, t_j$ 是不是 $> 0$ 来实现),然后如果 $i \operatorname{or} j = 11\dots 11$,那么这两个状态就可以满足我们的需求了(因为这说明每个位置都能找到至少一个 $\ge mid$ 的数字),将所选的两行数定为 $t_i$ 和 $t_j$ 即可。
代码如下,仅供参考:
#include <bits/stdc++.h> using namespace std; const int N = 3e5 + 5, M = 10; int n, m, a[N][M], b[N], t[1 << M], x, y; inline bool check(int mid) { memset(b, 0, sizeof b); memset(t, 0, sizeof t); for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) b[i] = (b[i] << 1) | (a[i][j] >= mid); t[b[i]] = i; } for(int i = 1; i < (1 << m); i++) for(int j = 1; j < (1 << m); j++) if((i | j) == (1 << m) - 1 && t[i] && t[j]) { x = t[i]; y = t[j]; return true; } return false; } int main() { ios::sync_with_stdio(false); cin >> n >> m; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) cin >> a[i][j]; int lb = -1, rb = 1e9; while(lb < rb) { int mid = lb + rb + 1 >> 1; if(check(mid)) lb = mid; else rb = mid - 1; } cout << x << ' ' << y << endl; return 0; }