CodeForces 1288D Minimax Problem

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;
}

猜你喜欢

转载自www.cnblogs.com/syksykCCC/p/CF1288D.html