P2985 [USACO10FEB] Chocolate Eating S 题解 二分答案
P2985 [USACO10FEB] Chocolate Eating S 题解
题目理解
首先,我们需要清楚地理解题目要求:
- 我们有\(N\)块巧克力,每块有一个特定的快乐值\(H_i\).
- 需要在\(D\)天内吃完这些巧克力
- 每天可以选择吃任意数量的巧克力(可以不吃,也可以全吃)
- 每天获得的快乐值是当天吃的所有巧克力的快乐值之和
- 需要最大化这\(D\)天中最小的每日快乐值(即最大化"最小日快乐")
解题思路
这个问题可以使用二分答案的方法来解决。具体思路如下:
二分搜索最小日快乐值:我们可以对可能的最小日快乐值进行二分搜索。对于每一个候选值,我们检查是否可以在\(D\)天内分配巧克力,使得每天的快乐值都不小于这个候选值。
检查可行性:对于给定的候选值\(mid\),我们需要判断是否存在一种分配方式满足条件。具体方法是贪心地分配巧克力,尽可能让每天的快乐值达到\(mid\),同时不超过D天。
算法步骤
- 确定二分范围:最小可能值是0,最大可能值是所有巧克力快乐值之和。
- 进行二分搜索:
- 取
mid = (left + right + 1) / 2 - 检查mid是否可行
- 如果可行,则尝试更大的值(
left = mid) - 否则尝试更小的值
(right = mid - 1)
- 取
- 检查可行性的方法:
- 从第一天开始,尽可能多吃巧克力直到当天快乐值\(≥mid\)
- 记录需要的天数
- 如果总天数\(≤D\),则可行
代码实现
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
int N, D;
vector<ll> H;
// 检查是否可以在D天内分配巧克力使得每天快乐值都不小于min_happy
bool check(ll min_happy)
{
ll cur = 0;
int days = 0;
for (int i = 0; i < N;)
{
while (i < N && cur < min_happy)
{
cur += H[i];
i++;
}
if (cur >= min_happy)
{
days++;
cur = 0;
}
if (days >= D)
return true;
}
return days >= D;
}
// 重建分配方案
vector<int> solve(ll min_happy)
{
vector<int> res(N, D); // 默认最后一天吃
ll cur = 0;
int day = 1;
for (int i = 0; i < N;)
{
int start = i;
while (i < N && cur < min_happy)
{
cur += H[i];
i++;
}
for (int j = start; j < i; j++)
{
res[j] = day;
}
if (cur >= min_happy)
{
day++;
cur = 0;
}
if (day > D)
break;
}
return res;
}
int main()
{
cin >> N >> D;
H.resize(N);
ll sum = 0;
for (int i = 0; i < N; i++)
{
cin >> H[i];
sum += H[i];
}
ll left = 0, right = sum;
ll best = 0;
// 二分查找最大可能的最小日快乐值
while (left <= right)
{
ll mid = (left + right) / 2;
if (check(mid))
{
best = mid;
left = mid + 1;
}
else
{
right = mid - 1;
}
}
cout << best << endl;
// 重建分配方案
vector<int> ans = solve(best);
for (int day : ans)
{
cout << day << endl;
}
return 0;
}
代码解释
check函数:检查给定的\(min\) \(happy\)是否可行。(
$min_happy$会变成\(min_happy\))通过贪心地分配巧克力,计算需要多少天才能满足每天快乐值\(≥min\) \(happy\)。solve函数:在找到最大\(min\) \(happy\)后,重建具体的分配方案。记录每块巧克力在哪一天被吃掉。
main函数:
- 读取输入数据
- 进行二分搜索找到最大可能的最小日快乐值
- 输出结果和分配方案
复杂度分析
- 时间复杂度:\(O(N log(sum(H_i)))\),其中\(sum(H_i)\)是所有巧克力快乐值的和。二分搜索需要\(O(log(sum(H_i)))\)次迭代,每次check需要\(O(N)\)时间。
- 空间复杂度:\(O(N)\),用于存储巧克力快乐值和分配方案。
注意事项
- 二分搜索的边界条件要正确处理,避免无限循环。
- 在重建分配方案时,要注意处理最后几天可能不需要吃满的情况。
- 题目要求输出方案时,如果有多解,输出最早达到最小快乐值的方案,我们的贪心方法自然满足这一条件。
25-8-8 补
朴素做法(非二分答案方法)题解
对于P2985这道题,除了二分答案的优化方法外,我们也可以考虑一种更直观的朴素做法。虽然时间复杂度较高,但对于理解问题本质很有帮助。
朴素思路
- 直接枚举最小日快乐值:从可能的最大值开始向下枚举,直到找到第一个可行的值。
- 验证每个候选值:对于每个候选的最小日快乐值,模拟分配过程,检查是否能在D天内完成分配。
- 记录最优解:一旦找到可行的分配方案,立即记录并输出结果。
算法步骤
- 计算所有巧克力快乐值总和sum
- 从sum/D开始向下枚举可能的最小日快乐值H
- 对于每个H:
- 模拟分配过程:每天尽可能多吃巧克力直到当天快乐值≥H
- 如果能在D天内分配完所有巧克力且满足每日≥H,则H就是解
- 输出最大的满足条件的H及其分配方案
代码实现
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
int N, D;
vector<ll> H;
// 检查给定min_happy是否可行,并返回分配方案
pair<bool, vector<int>> check_slow(ll min_happy)
{
vector<int> res(N, D); // 默认最后一天吃
ll cur = 0;
int day = 1;
int i = 0;
while (i < N && day <= D)
{
int start = i;
while (i < N && cur < min_happy)
{
cur += H[i];
i++;
}
for (int j = start; j < i; j++)
{
res[j] = day;
}
if (cur >= min_happy)
{
day++;
cur = 0;
}
}
bool ok = (i == N) && (day <= D + 1);
return {ok, res};
}
int main()
{
cin >> N >> D;
H.resize(N);
ll sum = 0;
for (int i = 0; i < N; i++)
{
cin >> H[i];
sum += H[i];
}
ll max_possible = sum / D;
ll best_h = 0;
vector<int> best_schedule;
// 从大到小枚举可能的最小日快乐值
for (ll h = max_possible; h >= 0; h--)
{
auto [ok, res] = check_slow(h);
if (ok) {
best_h = h;
best_schedule = res;
break; // 找到最大的可行h即可停止
}
}
cout << best_h << endl;
for (int day : best_schedule)
{
cout << day << endl;
}
return 0;
}
代码解释
check_slow函数:
- 尝试按照给定的\(min_happy\)分配巧克力
- 返回是否可行以及具体的分配方案
- 使用贪心方法,每天尽可能多吃直到达到\(min_happy\)
主函数:
- 读取输入数据
- 计算所有巧克力快乐值总和
- 从可能的最大值\(sum/D\)开始向下枚举
- 对每个候选值检查可行性
- 找到第一个可行的值即为解
- 输出结果和分配方案
复杂度分析
- 时间复杂度:\(O(sum/D × N)\),其中\(sum\)是所有巧克力快乐值的和。最坏情况下需要枚举\(sum/D\)次,每次检查需要\(O(N)\)时间。
- 空间复杂度:\(O(N)\),用于存储巧克力快乐值和分配方案。
优缺点
优点:
- 思路直观,易于理解和实现
- 不需要理解二分搜索等高级算法
缺点:
- 当\(sum\)很大时,枚举次数会非常多,效率低下
- 对于大规模数据无法在合理时间内完成
优化方向
这个朴素方法虽然简单,但对于较大的数据集显然不够高效。可以在此基础上进行以下优化:
- 从合理范围开始枚举:不必从0开始,可以从\(sum/D\)开始向下枚举
- 提前终止:一旦找到可行解立即终止,因为是从大到小枚举
- 转化为二分搜索:这正是我们之前给出的优化方法,将时间复杂度从\(O(sum/D × N)\)降为\(O(N log(sum))\)
qwq给个赞+关注吧QAQ
P2985 [USACO10FEB] Chocolate Eating S 题解 二分答案的更多相关文章
- luoguP2680 运输计划 题解(二分答案+树上差分)
P2680 运输计划 题目 这道题如果是看的我的树上差分来的,那么肯定一看题目就可以想到树上差分. 至于这是怎么想到的,一步一步来: 1.n有300000,不可能暴力枚举每一条边 2.因为我们要使运 ...
- 洛谷P3957 跳房子 题解 二分答案/DP/RMQ
题目链接:https://www.luogu.org/problem/P3957 这道题目我用到了如下算法: 线段树求区间最大值: 二分答案: DP求每一次枚举答案g时是否能够找到 \(\ge k\) ...
- 【bzoj4326】[NOIP2015]运输计划 二分答案+LCA
题目描述 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该 ...
- BZOJ 3993 Luogu P3324 [SDOI2015]星际战争 (最大流、二分答案)
字符串终于告一段落了! 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3993 (luogu) https://www.l ...
- POJ 3273 Monthly Expense 【二分答案】
题意:给出n天的花费,需要将这n天的花费分成m组,使得每份的和尽量小,求出这个最小的和 看题目看了好久不懂题意,最后还是看了题解 二分答案,上界为这n天花费的总和,下界为这n天里面花费最多的那一天 如 ...
- luoguP1419 寻找段落(二分答案+单调队列)
题意 给定一个长度为n的序列a1~an,从中选取一段长度在s到t之间的连续一段使其平均值最大.(n<=100000) 题解 二分答案平均值. judge时把每一个a[i]-mid得到b[i] 在 ...
- CF85E Guard Towers(二分答案+二分图)
题意 已知 N 座塔的坐标,N≤5000 把它们分成两组,使得同组内的两座塔的曼哈顿距离最大值最小 在此前提下求出有多少种分组方案 mod 109+7 题解 二分答案 mid 曼哈顿距离 >mi ...
- [USACO10FEB] 吃巧克力Chocolate Eating (二分答案)
题目链接 Solution 先直接二分答案,然后贪心判断,一旦少于答案就吃一块. 思路很简单,有一点细节. 一天内可以不吃巧克力. 注意处理最后时没吃完的全部在最后一天吃完. Code #includ ...
- P2985 [USACO10FEB]吃巧克力Chocolate Eating
P2985 [USACO10FEB]吃巧克力Chocolate Eating 题目描述 Bessie has received N (1 <= N <= 50,000) chocolate ...
- BZOJ 2016: [Usaco2010]Chocolate Eating( 二分答案 )
因为没注意到long long 就 TLE 了... 二分一下答案就Ok了.. ------------------------------------------------------------ ...
随机推荐
- Python 设置国内镜像
从Python官网下载.安装python之后(不建议使用brew安装python3) MacOS :打开/User/xxx/.config/pip/pip.conf Windows:打开%APPDAT ...
- Django Web应用开发实战第二章
一.基本配置信息 """ Django settings for myblog project. Generated by 'django-admin startproj ...
- 玩客云 OEC/OECT 笔记
外观 内部 PCB正面 PCB背面 PCB背面 RK3566 1Gbps PHY 配置 OEC 和 OECT(OEC-turbo) 都是基于瑞芯微 RK3566/RK3568 的网络盒子, 没有HDM ...
- 代码随想录第五天 | 哈希表part01
哈希表理论基础 建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map. 什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要 ...
- C#/.NET/.NET Core技术前沿周刊 | 第 40 期(2025年5.26-5.31)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...
- 【TrafficMonitor】无法显示13代intel的CPU温度
原因分析 TrafficMonitor的温度检测是利用了第三方软件LibreHardwareMonitor,并且这个问题可能与CPU有关 按照作者的指示,我们下载并启动了最新的LibreHardwar ...
- pont生成api涉及泛型问题
背景 pont是一款很好用的api生成工具. 我最近在用其生成swagger3的前端接口文件时,发现了个问题. 就是当我后端接口返回的是复杂类型的泛型的时候,生成的def类型有问题: 会直接写死泛型! ...
- Codeforces Round #563 (Div. 2) ABCD 题解
A. Ehab Fails to Be Thanos 题意:问你能否对a数组任意排序,使得前n段和不等于后n段和. 思路:水题,直接从小到大排序.这个情况都相等就一定无解. view code #in ...
- Node.js躬行记(30)——SkyWalking使用和排查分析
公司使用了阿里云的服务,其中可以在项目中使用全链路监测,最近要排查慢响应,所以就在 Node 项目中接了一下 SkyWalking. 本文还会记录在使用时遇到的问题,以及解决思路. 一.初始化 1)参 ...
- API管理平台,可视化统一管理企业API
API管理平台是为开发.产品.测试人员提供接口管理服务,帮助开发者更好地管理API接口,轻松实现创建.发布.维护API. 企业数字化转型为何需要用到API管理平台? 随着企业的不断发展,各类型的业务系 ...