P2985 [USACO10FEB] Chocolate Eating S 题解

题目理解

首先,我们需要清楚地理解题目要求:

  • 我们有\(N\)块巧克力,每块有一个特定的快乐值\(H_i\).
  • 需要在\(D\)天内吃完这些巧克力
  • 每天可以选择吃任意数量的巧克力(可以不吃,也可以全吃)
  • 每天获得的快乐值是当天吃的所有巧克力的快乐值之和
  • 需要最大化这\(D\)天中最小的每日快乐值(即最大化"最小日快乐")

解题思路

这个问题可以使用二分答案的方法来解决。具体思路如下:

  1. 二分搜索最小日快乐值:我们可以对可能的最小日快乐值进行二分搜索。对于每一个候选值,我们检查是否可以在\(D\)天内分配巧克力,使得每天的快乐值都不小于这个候选值。

  2. 检查可行性:对于给定的候选值\(mid\),我们需要判断是否存在一种分配方式满足条件。具体方法是贪心地分配巧克力,尽可能让每天的快乐值达到\(mid\),同时不超过D天。

算法步骤

  1. 确定二分范围:最小可能值是0,最大可能值是所有巧克力快乐值之和。
  2. 进行二分搜索:
    • mid = (left + right + 1) / 2
    • 检查mid是否可行
    • 如果可行,则尝试更大的值(left = mid)
    • 否则尝试更小的值(right = mid - 1)
  3. 检查可行性的方法:
    • 从第一天开始,尽可能多吃巧克力直到当天快乐值\(≥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;
}

代码解释

  1. check函数:检查给定的\(min\) \(happy\)是否可行。($min_happy$会变成\(min_happy\))通过贪心地分配巧克力,计算需要多少天才能满足每天快乐值\(≥min\) \(happy\)。

  2. solve函数:在找到最大\(min\) \(happy\)后,重建具体的分配方案。记录每块巧克力在哪一天被吃掉。

  3. main函数

    • 读取输入数据
    • 进行二分搜索找到最大可能的最小日快乐值
    • 输出结果和分配方案

复杂度分析

  • 时间复杂度:\(O(N log(sum(H_i)))\),其中\(sum(H_i)\)是所有巧克力快乐值的和。二分搜索需要\(O(log(sum(H_i)))\)次迭代,每次check需要\(O(N)\)时间。
  • 空间复杂度:\(O(N)\),用于存储巧克力快乐值和分配方案。

注意事项

  1. 二分搜索的边界条件要正确处理,避免无限循环。
  2. 在重建分配方案时,要注意处理最后几天可能不需要吃满的情况。
  3. 题目要求输出方案时,如果有多解,输出最早达到最小快乐值的方案,我们的贪心方法自然满足这一条件。

25-8-8 补

朴素做法(非二分答案方法)题解

对于P2985这道题,除了二分答案的优化方法外,我们也可以考虑一种更直观的朴素做法。虽然时间复杂度较高,但对于理解问题本质很有帮助。

朴素思路

  1. 直接枚举最小日快乐值:从可能的最大值开始向下枚举,直到找到第一个可行的值。
  2. 验证每个候选值:对于每个候选的最小日快乐值,模拟分配过程,检查是否能在D天内完成分配。
  3. 记录最优解:一旦找到可行的分配方案,立即记录并输出结果。

算法步骤

  1. 计算所有巧克力快乐值总和sum
  2. 从sum/D开始向下枚举可能的最小日快乐值H
  3. 对于每个H:
    • 模拟分配过程:每天尽可能多吃巧克力直到当天快乐值≥H
    • 如果能在D天内分配完所有巧克力且满足每日≥H,则H就是解
  4. 输出最大的满足条件的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;
}

代码解释

  1. check_slow函数

    • 尝试按照给定的\(min_happy\)分配巧克力
    • 返回是否可行以及具体的分配方案
    • 使用贪心方法,每天尽可能多吃直到达到\(min_happy\)
  2. 主函数

    • 读取输入数据
    • 计算所有巧克力快乐值总和
    • 从可能的最大值\(sum/D\)开始向下枚举
    • 对每个候选值检查可行性
    • 找到第一个可行的值即为解
    • 输出结果和分配方案

复杂度分析

  • 时间复杂度:\(O(sum/D × N)\),其中\(sum\)是所有巧克力快乐值的和。最坏情况下需要枚举\(sum/D\)次,每次检查需要\(O(N)\)时间。
  • 空间复杂度:\(O(N)\),用于存储巧克力快乐值和分配方案。

优缺点

优点

  • 思路直观,易于理解和实现
  • 不需要理解二分搜索等高级算法

缺点

  • 当\(sum\)很大时,枚举次数会非常多,效率低下
  • 对于大规模数据无法在合理时间内完成

优化方向

这个朴素方法虽然简单,但对于较大的数据集显然不够高效。可以在此基础上进行以下优化:

  1. 从合理范围开始枚举:不必从0开始,可以从\(sum/D\)开始向下枚举
  2. 提前终止:一旦找到可行解立即终止,因为是从大到小枚举
  3. 转化为二分搜索:这正是我们之前给出的优化方法,将时间复杂度从\(O(sum/D × N)\)降为\(O(N log(sum))\)

qwq给个赞+关注吧QAQ

P2985 [USACO10FEB] Chocolate Eating S 题解 二分答案的更多相关文章

  1. luoguP2680 运输计划 题解(二分答案+树上差分)

    P2680 运输计划  题目 这道题如果是看的我的树上差分来的,那么肯定一看题目就可以想到树上差分. 至于这是怎么想到的,一步一步来: 1.n有300000,不可能暴力枚举每一条边 2.因为我们要使运 ...

  2. 洛谷P3957 跳房子 题解 二分答案/DP/RMQ

    题目链接:https://www.luogu.org/problem/P3957 这道题目我用到了如下算法: 线段树求区间最大值: 二分答案: DP求每一次枚举答案g时是否能够找到 \(\ge k\) ...

  3. 【bzoj4326】[NOIP2015]运输计划 二分答案+LCA

    题目描述 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该 ...

  4. BZOJ 3993 Luogu P3324 [SDOI2015]星际战争 (最大流、二分答案)

    字符串终于告一段落了! 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3993 (luogu) https://www.l ...

  5. POJ 3273 Monthly Expense 【二分答案】

    题意:给出n天的花费,需要将这n天的花费分成m组,使得每份的和尽量小,求出这个最小的和 看题目看了好久不懂题意,最后还是看了题解 二分答案,上界为这n天花费的总和,下界为这n天里面花费最多的那一天 如 ...

  6. luoguP1419 寻找段落(二分答案+单调队列)

    题意 给定一个长度为n的序列a1~an,从中选取一段长度在s到t之间的连续一段使其平均值最大.(n<=100000) 题解 二分答案平均值. judge时把每一个a[i]-mid得到b[i] 在 ...

  7. CF85E Guard Towers(二分答案+二分图)

    题意 已知 N 座塔的坐标,N≤5000 把它们分成两组,使得同组内的两座塔的曼哈顿距离最大值最小 在此前提下求出有多少种分组方案 mod 109+7 题解 二分答案 mid 曼哈顿距离 >mi ...

  8. [USACO10FEB] 吃巧克力Chocolate Eating (二分答案)

    题目链接 Solution 先直接二分答案,然后贪心判断,一旦少于答案就吃一块. 思路很简单,有一点细节. 一天内可以不吃巧克力. 注意处理最后时没吃完的全部在最后一天吃完. Code #includ ...

  9. P2985 [USACO10FEB]吃巧克力Chocolate Eating

    P2985 [USACO10FEB]吃巧克力Chocolate Eating 题目描述 Bessie has received N (1 <= N <= 50,000) chocolate ...

  10. BZOJ 2016: [Usaco2010]Chocolate Eating( 二分答案 )

    因为没注意到long long 就 TLE 了... 二分一下答案就Ok了.. ------------------------------------------------------------ ...

随机推荐

  1. Python 设置国内镜像

    从Python官网下载.安装python之后(不建议使用brew安装python3) MacOS :打开/User/xxx/.config/pip/pip.conf Windows:打开%APPDAT ...

  2. Django Web应用开发实战第二章

    一.基本配置信息 """ Django settings for myblog project. Generated by 'django-admin startproj ...

  3. 玩客云 OEC/OECT 笔记

    外观 内部 PCB正面 PCB背面 PCB背面 RK3566 1Gbps PHY 配置 OEC 和 OECT(OEC-turbo) 都是基于瑞芯微 RK3566/RK3568 的网络盒子, 没有HDM ...

  4. 代码随想录第五天 | 哈希表part01

    哈希表理论基础 建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map. 什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要 ...

  5. C#/.NET/.NET Core技术前沿周刊 | 第 40 期(2025年5.26-5.31)

    前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...

  6. 【TrafficMonitor】无法显示13代intel的CPU温度

    原因分析 TrafficMonitor的温度检测是利用了第三方软件LibreHardwareMonitor,并且这个问题可能与CPU有关 按照作者的指示,我们下载并启动了最新的LibreHardwar ...

  7. pont生成api涉及泛型问题

    背景 pont是一款很好用的api生成工具. 我最近在用其生成swagger3的前端接口文件时,发现了个问题. 就是当我后端接口返回的是复杂类型的泛型的时候,生成的def类型有问题: 会直接写死泛型! ...

  8. Codeforces Round #563 (Div. 2) ABCD 题解

    A. Ehab Fails to Be Thanos 题意:问你能否对a数组任意排序,使得前n段和不等于后n段和. 思路:水题,直接从小到大排序.这个情况都相等就一定无解. view code #in ...

  9. Node.js躬行记(30)——SkyWalking使用和排查分析

    公司使用了阿里云的服务,其中可以在项目中使用全链路监测,最近要排查慢响应,所以就在 Node 项目中接了一下 SkyWalking. 本文还会记录在使用时遇到的问题,以及解决思路. 一.初始化 1)参 ...

  10. API管理平台,可视化统一管理企业API

    API管理平台是为开发.产品.测试人员提供接口管理服务,帮助开发者更好地管理API接口,轻松实现创建.发布.维护API. 企业数字化转型为何需要用到API管理平台? 随着企业的不断发展,各类型的业务系 ...