CF1619D. New Year's Problem


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


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM