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