洛谷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;
}

posted @ 2025-04-09 13:33  2789617221guo  阅读(47)  评论(0)    收藏  举报