1. 程式人生 > 其它 >CF1623C Balanced Stone Heaps

CF1623C Balanced Stone Heaps

CF1623C

原題連結←Click it

題目大意:有\(i(i >= 3)\)堆石子,每堆石子的個數為\(h_i\),現在從第\(3\)堆到第\(n\)堆石子進行操作,每次都可以選擇\(d\)個石頭,使得\(h_{i - 2} += 2 * d\)\(h_{i_1} += d\)\(h_i -= 3 * d\)。求操作完成之後數量最少的堆中石子可能的最大值。

解題思路:顯然是一個二分查詢,但是check函式在寫的過程中有些波折。剛開始的時候我是選擇從順序模擬,但是發現對第\(i\)堆石子操作的時候,發現如果第\(i - 2\)堆石子滿足條件,但是第\(i - 1\)堆石子不滿足條件的情況下,我們就必須要考慮第\(i + 1\)

堆石子對\(i - 1\)堆的貢獻。也就是說從順序模擬需要考慮之後的不確定因素,但是逆序模擬的時候,可以貪心地讓第\(i\)堆石子剩下可能的最小值,因為前面的堆無法影響到後面的堆,因此理論上我們對第\(i\)堆石子每次可移動的\(d =\lfloor \frac{nh[i] - m}{3} \rfloor\),但是實際上在順序模擬的過程中發現每堆石子可移動的\(d <= \lfloor \frac{h[i]}{3}\rfloor\),因此我們可以貪心地取\(d = min(\lfloor \frac{nh[i] - m}{3} \rfloor,\lfloor \frac{h[i]}{3}\rfloor)\)
,並檢查每個\(nh[i]\)是否大於\(m\)

參考程式碼:

vector<int> h;
bool check(int m) {
    vector<int> nh = h;
    for(int i = nh.size() - 1; i >= 2; i --) {
        if(nh[i] < m) return 0;
        int d = min(h[i], nh[i] - m) / 3;
        nh[i - 1] += d;
        nh[i - 2] += 2 * d;
    }
    return b[0] >= m && b[1] >= m;
}
void solve() {
    int n;
    cin >> n;
    a.resize(n);
    int l = INF, r = INF;

    for(int i = 0; i < n;i ++) {
        cin >> a[i];
        l = min(l, a[i]);
    }
    while(l < r) {
        int m = l + r + 1 >> 1;
        if(check(m)) l = m;
        else r = m - 1;
    }
    cout << l << '\n';
}