题解:洛谷 P1843 奶牛晒衣服
【题目来源】
【题目描述】
熊大妈决定给每个牛宝宝都穿上可爱的婴儿装。但是由于衣服很湿,为牛宝宝晒衣服就成了很不爽的事情。于是,熊大妈请你(奶牛)帮助她完成这个重任。
一件衣服在自然条件下用一秒的时间可以晒干 \(a\) 点湿度。抠门的熊大妈只买了一台烘衣机。使用用一秒烘衣机可以让一件衣服额外烘干 \(b\) 点湿度(一秒晒干 \(a+b\) 湿度),但在同一时间内只能烘一件衣服。现在有 \(n\) 件衣服,第 \(i\) 衣服的湿度为 \(w_i\)(保证互不相同),要你求出弄干所有衣服的最少时间(湿度为 \(0\) 为干)。
【输入】
第一行三个整数,分别为 \(n,a,b\)。
接下来 \(2\) 到 \(n+1\) 行,第 \(i\) 行输入 \(w_i\)。
【输出】
一行,弄干所有衣服的最少时间。
【输入样例】
3 2 1
1
2
3
【输出样例】
1
【核心思想】
-
问题分析:有 \(n\) 件衣服,第 \(i\) 件初始湿度为 \(w_i\)。自然条件下每件衣服每秒减少 \(a\) 点湿度;另外有一台烘干机,每秒可以让一件衣服额外减少 \(b\) 点湿度(即该件衣服每秒总减少 \(a+b\)),但同一时间只能烘干一件衣服。所有衣服同时自然晾干,且烘干机可以任意切换服务对象,求弄干所有衣服所需的最少时间。由于时间增加时可行性单调,这是一个典型的二分答案 + 贪心判定问题。
-
算法选择:
- 二分答案:对时间 \(t\) 进行二分,判定在 \(t\) 秒内能否将所有衣服弄干。
- 贪心判定:在 \(t\) 秒内,每件衣服自然晾干 \(a \cdot t\) 点湿度。若 \(w_i > a \cdot t\),则剩余 \(w_i - a \cdot t\) 点湿度必须依靠烘干机处理。由于烘干机每件衣服每秒额外烘干 \(b\) 点,第 \(i\) 件衣服需要的烘干机时间为 \(\left\lceil \frac{w_i - a \cdot t}{b} \right\rceil\)(若分子≤0则为0)。所有衣服需要的烘干机总时间若不超过 \(t\),则 \(t\) 秒可行;否则不可行。
- 单调性:\(t\) 越大,可行性越强,因此可以二分。
-
关键步骤:
- 读入数据:\(n, a, b\) 以及 \(n\) 个初始湿度 \(w_i\)。
- 二分边界:左边界 \(l = 0\),右边界 \(r = \max(w_i)\)(因为最坏情况下需 \(\max(w_i)/a\) 秒自然晾干,但也可设 \(r = 10^9\) 或 \(10^6\) 安全值)。
- 判定函数
check(mid):- 计算自然晾干量
natural = a * mid。 - 初始化
total_time = 0。 - 遍历每件衣服,若
w_i > natural,则计算need = (w_i - natural + b - 1) / b,累加到total_time。 - 若
total_time <= mid,返回true,否则false。
- 计算自然晾干量
- 二分过程:
while (l < r),取mid = (l + r) / 2,若check(mid)为真,则r = mid,否则l = mid + 1。 - 输出:
l即为最少时间。
-
时间/空间复杂度:
- 时间复杂度:\(O(n \log \max(w_i))\),二分约 \(30\) 次,每次判定 \(O(n)\)。
- 空间复杂度:\(O(n)\),存储湿度数组。
-
二分答案 + 贪心判定的核心思想:
- 可行性单调性:若 \(t\) 秒内能弄干所有衣服,则任何更大的时间也能,因此可以二分。
- 贪心分配烘干机:烘干机的作用是弥补自然晾干的不足。每件衣服所需烘干机时间独立计算,总时间需求为各件衣服需求之和。由于烘干机可以任意切换且不影响效率,只要总需求不超过 \(t\),就一定能安排得下(例如按任意顺序连续工作)。
- 向上取整处理:使用
(剩余湿度 + b - 1) / b计算需要的秒数,避免浮点数误差。 - 适用场景:适用于资源分配、分批处理、最小最大时间类问题,当判定函数简单且单调时,二分答案是最佳选择。
【算法标签】
普及 #贪心
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n; // 衣服数量
int a; // 自然晾干速度
int b; // 烘干机烘干速度
priority_queue<int> q; // 大根堆,存储衣服湿度
int tim = 0; // 总时间
int mx; // 当前最大湿度
int main()
{
// 输入衣服数量、自然晾干速度和烘干机烘干速度
cin >> n >> a >> b;
// 输入每件衣服的初始湿度
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
q.push(x); // 将湿度加入优先队列
}
// 初始化当前最大湿度
mx = q.top();
q.pop();
// 循环处理直到最大湿度满足条件
while (mx > tim * a)
{
tim++; // 时间增加1单位
mx -= b; // 使用烘干机烘干
q.push(mx); // 将处理后的湿度重新放入队列
mx = q.top(); // 获取新的最大湿度
q.pop();
}
// 输出总时间
cout << tim;
return 0;
}
【运行结果】
3 2 1
1
2
3
1
浙公网安备 33010602011771号