[二分答案][状压] Codeforces 1288D Minimax Problem
题目大意
给出一个 \(N\) 行 \(M\) 列的数字矩阵 \(a\) ,找出两行 \(x,y\),令\(b_j=max(a_{x,j},a_{y,j})\),试使得\(\mathop{min}\limits_{1\leq j\leq M} b_j\) 最大,输出选择的 \(x,y\) ,可以相同。
题解
首先考虑二分答案去求最小值的最大值。那么问题就转化为如何去判断是否存在两行的最小值大于mid。
因为列数只有8,所以考虑去状压。对于任意一行,它的某一列上的数若大于等于mid,则记为1,若小于mid,则记为0,则一共有\(2^8=256\)种情况。把这256种情况暴力两两按位或,若按位或的结果等于\((11111111)_2\),则\(Ans>mid\),否则\(Ans<=mid\)。
时间复杂度\(O((2^{2M}+N)logN)\)。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
int Data[300010][9],Hash[300];
int N,M,A,B;
bool Judge(int x){
memset(Hash,0,sizeof(Hash));
for(RG i=1;i<=N;++i){
int num=0;
for(RG j=1;j<=M;++j)
if(Data[i][j]>=x) num|=1<<(j-1);
Hash[num]=i;
}
for(RG i=0;i<(1<<M);++i)
for(RG j=i;j<(1<<M);++j)
if(Hash[i] && Hash[j] && (i|j)==(1<<M)-1){
A=Hash[i];B=Hash[j];return true;
}
return false;
}
inline void Solve(){
int L=0,R=1000000000,Res,AnsA,AnsB;
while(L<=R){
int mid=(L+R)>>1;
if(Judge(mid)){Res=mid;AnsA=A;AnsB=B;L=mid+1;}
else R=mid-1;
}
printf("%d %d\n",AnsA,AnsB);
return;
}
int main(){
Read(N);Read(M);
for(RG i=1;i<=N;++i)
for(RG j=1;j<=M;++j)
Read(Data[i][j]);
Solve();
return 0;
}