【二分】[USACO 2010 Feb S]Chocolate Eating

peterzh6發表於2024-10-05

https://ac.nowcoder.com/acm/contest/22353/E
有的時候50%通不過真的很無助orz

二分查詢最小幸福值: 我們希望找出一個最大的 mid,即最小幸福值,使得 Bessie 能夠在 d 天內吃完巧克力,並且每天的幸福值都不低於這個 mid。

我們可以透過二分查詢的方式來確定這個 mid。mid 的初始範圍是 [0, 1e12],因為幸福值可能很大。
每次我們計算出 mid 的值後,使用 check() 函式來驗證是否能夠在 d 天內滿足每天的幸福值都不低於 mid。如果可以,我們嘗試增大 mid;如果不行,我們嘗試減小 mid。

注意 如果有剩餘巧克力,需要分配到最後一天,不能有剩餘

  1. 設定二分查詢的上下界 low = 0, high = 1e12
  2. 進行二分查詢:
    a. 計算 mid = (low + high) / 2
    b. 使用 check(mid) 判斷是否可以分配巧克力:
    - 如果可以滿足最小幸福值為 mid,更新結果,並嘗試更大的 mid(low = mid + 1)
    - 如果不可以滿足,嘗試更小的 mid(high = mid - 1)
  3. 輸出二分查詢的結果(最大最小幸福值)
  4. 輸出巧克力的分配方案
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll n, d;
ll a[50050], happiness[50050], ans[50010];

int check(ll mid) {
    ll i, j, count, sum, tmp[50010];
    count = sum = 1;

    happiness[1] = 0;
    for(i = 1; i <= d; i++) {
        while(happiness[i] < mid) {
            if(count > n) return -1;  // 巧克力吃完了,返回 -1
            tmp[count] = i;  // 記錄巧克力被吃掉的天數
            happiness[i] += a[count++];  // 增加當前天的幸福值
        }
        happiness[i + 1] = happiness[i] / 2;  // 下一天的幸福值是前一天的一半
    }

    for(i = 1; i < count; i++) ans[i] = tmp[i];  // 記錄巧克力的分配天數
    for(i = count; i <= n; i++) ans[i] = d;  // 剩餘巧克力分配到最後一天
    return 1;
}

int main() {
    cin >> n >> d;
    
    for(int i = 1; i <= n; i++) cin >> a[i];

    ll l = 0, r = 1e12;
    ll result = 0;

    // 二分查詢尋找最大的最小幸福值
    while(l <= r) {
        ll mid = (l + r) >> 1;

        if(check(mid) == 1) result = mid, l = mid + 1;
        else r = mid - 1;
    }

    cout << result << endl;
    for(int i = 1; i <= n; i++) cout << ans[i] << endl;
}

相關文章