CF1619D. New Year's Problem
大致题意
Vlad要给 \(n\) 个朋友买礼物,有 \(m\) 个商店。定义 \(p_{ij}\) 为从第 \(i\) 个商店给第 \(j\) 个朋友买礼物产生的快乐值(由矩阵给出)。定义 \(α\) 为所有朋友的快乐值的最小值。Vlad最多访问 \(n-1\) 个商店,给每一位朋友买一样礼物,问 \(α\) 值最大是多少。
解题思路(二分)
遇到这种求最小值最大的题,很快就可以想到使用二分解决。这道题的关键在于考虑判断能否实现的check函数怎么实现。
在check函数中,如果当前值 \(x\) 想要可成立,需要满足两个条件
① 所有的朋友都至少有一个商店能买到快乐值大于等于 \(x\) 的礼物
② 最多只访问 \(n-1\) 个商店
第一个要求我们可以很方便的实现,只需要开一个大小为 \(n\) 的数组,遍历统计这个朋友能否成功买到合适礼物。
对于第二个要求,我们可以转化,为一个商店是否能过同时满足大于两个人的要求,如果可以,说明最多只用访问 \(n-1\) 个商店。
原因如下,如果每一个朋友都有一个对应的商店可以买到对应合适礼物,此时需要访问 \(n\) 个商店。此时还有一个商店能买到两个人的礼物,那么这两个人可以都去这个商店买,那么需要的总商店数变为 \(n-1\) 个商店。
这样我们就可以实现check函数,用二分完成要求。
解题思路(排序)
赛后在看大佬代码的时候看到了一种不一样的代码
Submission #140035383 - Codeforces
int ans = 0;
for (int j = 0; j < m; j++){
vector<int> p2 = p[j];
sort(p2.begin(), p2.end(), greater<int>());
ans = max(ans, p2[1]);
}
for (int j = 0; j < n; j++){
int mx = 0;
for (int k = 0; k < m; k++){
mx = max(mx, p[k][j]);
}
ans = min(ans, mx);
}
不用二分,非常简短的做出了这题。
稍微的研究了一下,说一下自己的理解
这种做法的核心思想与二分的check函数类似。可以概括为一句话:满足所有人都被选到的同时,让一个商店满足两个人。
前面的一重循环+排序,作用就是找出,如果要让一个商店满足两个人,那么最大能给出的快乐值是多少。(而且这个值是最优的)
循环结束后,得到的 \(ans\) 中,储存的是取了两个人的商店,他对于答案的贡献。
后面的循环就比较简单,就是找出对于一个人,礼物最大的快乐值。
将这些值去min,就得到了最终答案。
代码(二分)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5;
vector<int> sp[maxn + 10];
int n, m;
bool check(int x)
{
vector<bool> f(n + 10);
bool ff = false;
for (int i = 1; i <= m; i++) {
int cnt = 0;
for (int j = 1; j <= n; j++) {
if (sp[i][j] >= x) {
cnt++;
f[j] = 1;
}
}
if (cnt >= 2)
ff = true;
}
if (!ff)
return false;
for (int i = 1; i <= n; i++) {
if (!f[i])
return false;
}
return true;
}
void solve()
{
cin >> m >> n;
int mx = 0;
for (int i = 1; i <= m; i++) {
sp[i].clear();
sp[i].emplace_back(0);
for (int j = 1; j <= n; j++) {
int t;
cin >> t;
sp[i].emplace_back(t);
mx = max(t, mx);
}
}
int l = 0, r = mx;
int ans = 0;
while (l <= r) {
int mid = (l + r) / 2;
if (check(mid)) {
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
}
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}