题解:洛谷 P1843 奶牛晒衣服

【题目来源】

洛谷: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

【核心思想】

  1. 问题分析:有 \(n\) 件衣服,第 \(i\) 件初始湿度为 \(w_i\)。自然条件下每件衣服每秒减少 \(a\) 点湿度;另外有一台烘干机,每秒可以让一件衣服额外减少 \(b\) 点湿度(即该件衣服每秒总减少 \(a+b\)),但同一时间只能烘干一件衣服。所有衣服同时自然晾干,且烘干机可以任意切换服务对象,求弄干所有衣服所需的最少时间。由于时间增加时可行性单调,这是一个典型的二分答案 + 贪心判定问题。

  2. 算法选择

    • 二分答案:对时间 \(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\) 越大,可行性越强,因此可以二分。
  3. 关键步骤

    • 读入数据\(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 即为最少时间。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \log \max(w_i))\),二分约 \(30\) 次,每次判定 \(O(n)\)
    • 空间复杂度:\(O(n)\),存储湿度数组。
  5. 二分答案 + 贪心判定的核心思想

    • 可行性单调性:若 \(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
posted @ 2026-09-03 14:15  团爸讲算法  阅读(6)  评论(0)    收藏  举报