题目链接:点这里~
题目大意
n哥队员每个队员有5个能力值,现在需要挑出3个队员,m1,m2,m3,m4,m5分别是每个能力值在这3个队员中的最大值,s是五个最大值的最小值。求挑选队员,使得s最大。3≤N≤3000
思路
最小值最大,那么肯定要考虑二分了,二分的关键在于怎么写这个check函数。求的是五个最大能力值中的最小值最大,那么这五个最大能力值肯定都得大于mid。
因为只有五种能力,所以可以用五位的二进制记录状态,表示当前能力值是否>=mid,并标记该状态,表示存在该状态,然后枚举三个存在的状态看看这三个状态的或运算(|)是不是31(11111),如果是,说明五个最大能力值都>=mid,满足条件的。
ac代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
int a[3050][6], n;
bool check(int x){
map<int,int> mp;
for(int i = 1; i <= n; i ++){
int tmp = 0;
for(int j = 0; j < 5; j ++){
if(a[i][j] >= x) tmp |= (1 << j); //大于mid的能力值都是可取,更新状态
mp[tmp] ++;
}
}
//枚举三个状态,取同一个状态可以理解为如果可以的话,那就是两个状态或者一个状态达到了31(11111),剩下的可以随便取
for(auto _i : mp)
for(auto _j : mp)
for(auto _k : mp)
if((_i.first|_j.first|_k.first) == (1<<5) - 1) return true;
return false;
}
int main(){
cin >> n;
for(int i = 1; i <= n; i ++) for(int j = 0; j < 5; j ++) cin >> a[i][j];
int l = 1, r = 1e9, ans = 1;
while(l <= r){
int mid = l + r >> 1;
if(check(mid)) l = mid + 1, ans = mid;
else r = mid - 1;
}
cout << ans << endl;
return 0;
}