洛谷P2985 [USACO10FEB] Chocolate Eating S 题解
本题做法
- 二分,贪心。
思路
二分答案,每次使用 \(check\) 函数检验。
\(check\) 函数:定义 2 个变量 \(now\) 和 \(nxt\),分别代表当前快乐值以及下一块要吃的巧克力。从 1 遍历到 \(d\),每次先将 \(now\) 除以 2,若 \(now<mid\),则一直吃下一块巧克力,直到 \(now\ge mid\) 或者 \(nxt>n\),若吃完后 \(now<mid\),则代表没得吃且不符合 \(mid\) 了,直接返回 false。在函数结束时,记得将 \(record\)(记录每块巧克力什么时候吃的)剩余的 \(nxt\sim n\) 设置成 \(d\)。
若 \(check(mid)\) 成立,则 copy(record+1,record+1+n,ans+1)
,最后输出 \(l\) 和 \(ans\) 即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+5;
int n,d,h[N],ans[N],record[N];
inline bool check(long long mid){
long long now=0,nxt=1;
for(int i=1;i<=d;i++){
now/=2;
while(now<mid&&nxt<=n) {
record[nxt]=i;
now+=h[nxt++];
}
if(now<mid) return 0;
}
for(int i=nxt;i<=n;i++) record[i]=d;
return 1;
}
int main(){
cin>>n>>d;
for(int i=1;i<=n;i++) cin>>h[i];
long long l=-1,r=5e10+1;//5e4*1e6=5e10
while(l+1<r){
long long mid=l+(r-l)/2;
if(check(mid)) {
l=mid;
copy(record+1,record+1+n,ans+1);
}
else r=mid;
}
cout<<l<<endl;
for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
return 0;
}