Cutting Cake

#二分 #前缀和
爱丽丝正在参加疯帽子的茶会!有一个长条蛋糕,由 n 个部分组成,美味值为 a1,a2,…,ana 。茶会上有 m 个生物,不包括爱丽丝。

爱丽丝会把蛋糕切成 m+1 块。从形式上看,她会将蛋糕分割成 m+1 个子数组,其中每个子数组由一定数量的相邻部分组成。一块蛋糕的美味程度是其各部分美味程度的总和。之后,她会把这些 m+1 碎片分给 m 个生物和她自己(她的碎片可以是空的)。然而,只有当每个 m 生物的美味度达到或超过 v 时,它们才会感到快乐。

爱丽丝希望确保每个生物都快乐。受限于这个条件,她也想让自己的棋子美味度最大化。你能帮爱丽丝找到她的棋子的最大美味度吗?如果无法确保每个生物都快乐,则输出 −1。


Alice的答案区间为[i,j],暴力枚举所有可能的情况。
用前缀,后缀信息记录从[:i],[i:]的最多可能情况。
枚举i,对于每一个i,右区间可以二分来枚举满足所有可能情况的j的最大值。


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int ll

// ll sum[N];
// int pre[N], suf[N];  // 表示[:i],[i:] 有多少个满足条件的
void solve() {
    int n, m, v;
    cin >> n >> m >> v;
    vector<int> a(n+1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    vector<int> sum(n+1,0),pre(n+2),suf(n+2);
    for (int i = 1; i <= n; i++) {
        sum[i] = sum[i-1] + a[i]; 
    }
    int tmp = 0;
    for (int i = 1; i <= n; i++) {
        tmp += a[i];
        pre[i] = pre[i-1];
        if (tmp >= v) {
            tmp = 0;
            pre[i]++;
        }
    }
    tmp = 0;
    for (int i = n; i >= 1; i--) {
        tmp += a[i];
        suf[i] = suf[i+1];
        if (tmp >= v) {
            tmp = 0;
            suf[i]++;
        }
    }
    if (suf[1] < m) {
        cout << -1 << endl;
        return;
    }
    int mx = 0;
    for (int i = 1; i <= n; i++) {
        int L = i, R = n;
        while(L <= R) {
            int mid = (L+R) >> 1;
            if (pre[i-1]+suf[mid+1] >= m) {
                mx = max(sum[mid]-sum[i-1],mx);
                L = mid + 1;
            } else {
                R = mid - 1;
            }
        }
    }
    cout << mx << endl;
}

signed main() {
    cin.tie(nullptr)->ios::sync_with_stdio(false);
    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
} /* created: 2024-12-10 16:44 author: Egrvigrf */
github