Solutions P2985 [USACO10FEB] Chocolate Eating S
思路
很明显的贪心+二分,具体就是尽可能的每天少吃,怎么用二分结合呢我们check一个x如果x小于了当天的起床时候的幸福值那么就直接睡觉否则就一直吃吃到大于等于如果全部吃完还不够那就失败了(题目里面虽然没有说但是数据点没有)这里的x就是我们的目标下界因为我们要最小值最大化所以我们期望的是让每一天的幸福值至少达到x,做法上去二分答案那个x就可以了。
时间复杂度就是 \(\Theta((N + D) \log \sum H_i)\)。
对固定下界 \(x\),check 时每天若 \(cur<x\) 就从当前指针开始按顺序吃到第一次使 \(cur\ge x\) 为止 \(H_i>0\),吃更多只会更早耗尽巧克力,对未来没有额外好处),因此这是达到每日约束的最省策略;若该最省策略都失败 \(吃完仍 <x\),任何方案都不可能成功。可行性对 \(x\) 单调,所以二分最大可行 \(x\)。
实现
AClink。
Accepted Code (C++17)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define i128 __int128
#define ld long double
#define fir first
#define sec second
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lowbit(x) (x&-x)
using namespace std;
const int MOD=998244353;
const int MOD1=1e9+7;
//char ibuf[1<<25],*p1=buf,*p2=buf;
mt19937 mrand(random_device{}());
int rnd(int x){ return mrand() % x;}
ll qpow(ll a,ll b){ll res=1;while(b){if(b&1)res=res*a%MOD;a=a*a%MOD,b>>=1;}return res;}
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){ return a/gcd(a,b)*b;}
//C++ 17 -O2
//By MaZhaoze
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, D;
cin >> N >> D;
vector<ll> H(N);
ll sumH = 0;
for (int i = 0; i < N; i++) {
cin >> H[i];
sumH += H[i];
}
auto feasible = [&](ll X) -> bool {
int idx = 0;
ll cur = 0;
for (int day = 1; day <= D; day++) {
while (cur < X && idx < N) {
cur += H[idx];
idx++;
}
if (cur < X) return false;
cur /= 2;
}
return true;
};
ll lo = 0, hi = sumH;
while (lo < hi) {
ll mid = (lo + hi + 1) / 2;
if (feasible(mid)) lo = mid;
else hi = mid - 1;
}
ll best = lo;
vector<int> dayEat(N, D);
int idx = 0;
ll cur = 0;
for (int day = 1; day <= D; day++) {
while (cur < best && idx < N) {
cur += H[idx];
dayEat[idx] = day;
idx++;
}
cur /= 2;
// if (idx >= N) {
// }
}
while (idx < N) {
dayEat[idx] = D;
idx++;
}
cout << best << "\n";
for (int i = 0; i < N; i++) {
cout << dayEat[i] << "\n";
}
return 0;
}

浙公网安备 33010602011771号