文章

【GESP】C++五级练习题 luogu-P1843 奶牛晒衣服

GESP C++ 五级练习题,二分答案和贪心思想考点应用,五级考生可以练习。题目难度⭐⭐⭐☆☆,洛谷难度等级普及/提高−

luogu-P1843 奶牛晒衣服

题目要求

题目背景

熊大妈决定给每个牛宝宝都穿上可爱的婴儿装 。但是由于衣服很湿,为牛宝宝晒衣服就成了很不爽的事情。于是,熊大妈请你(奶牛)帮助她完成这个重任。

题目描述

一件衣服在自然条件下用一秒的时间可以晒干 $a$ 点湿度。抠门的熊大妈只买了一台烘衣机 。使用用一秒烘衣机可以让一件衣服额外烘干 $b$ 点湿度(一秒晒干 $a+b$ 湿度),但在同一时间内只能烘一件衣服。现在有 $n$ 件衣服,第 $i$ 衣服的湿度为 $w_i$(保证互不相同),要你求出弄干所有衣服的最少时间(湿度为 $0$ 为干 )。

输入格式

第一行三个整数,分别为 $n,a,b$。
接下来 $2$ 到 $n+1$ 行,第 $i$ 行输入 $w_i$。

输出格式

一行,弄干所有衣服的最少时间。

输入输出样例 #1

输入 #1
1
2
3
4
3 2 1
1
2
3
输出 #1
1
1

说明/提示

样例解释

让机器烘第三件衣服即可一秒完成。

数据范围

$1 \le w_i,a,b,n \le 5 \times 10^5$


题目分析

这是一道典型的二分答案题目,结合了贪心思想。

1. 问题分析

我们需要求出弄干所有衣服的最少时间。

  • 时间越长,衣服越容易干,满足单调性
  • 因此可以使用二分答案算法来搜索最少时间。

2. 解题思路

假设我们需要 mid 秒来晒干衣服。在这个时间内:

  1. 自然晒干:每件衣服都会自然减少 mid * a 的湿度。
  2. 烘干机额外贡献:如果某件衣服在自然晒干后还没干(即 $w_i > mid \times a$),就需要使用烘干机。题目指出烘干机每秒减少 $a+b$ 湿度,相对于自然晒干,它每秒额外提供 $b$ 点湿度的消除。
  3. 贪心策略:计算必须使用烘干机的时间。
  • 首先假设所有时间都在自然晒干,减少湿度 $mid \times a$。
  • 如果某件衣服仍未干,说明剩下的湿度 $need = w_i - mid \times a$ 需要靠烘干机的额外效率来消除。
  • 烘干机每秒提供 $a+b$ 的湿度消除,比自然晒干多消除 $b$。因此,每使用烘干机 1 秒,实际上是额外消除了 $b$ 点湿度。
  • 需要使用烘干机的时间 $t_i = \lceil \frac{need}{b} \rceil$。代码写作 (need + b - 1) / b
  1. 判定条件:统计所有衣服需要的烘干机总时间 $\sum t_i$。由于只有一台机器,如果 $\sum t_i \le mid$,说明时间 mid 可行;否则不可行。

3. 复杂度分析

  • 二分次数:约 $\log(\max(w_i))$ 次。
  • Check函数:每次检查需要遍历 $N$ 件衣服,复杂度 $O(N)$。
  • 总复杂度:$O(N \log(\max(w_i)))$。对于 $N=5 \times 10^5$,计算量在合理范围内。


示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <algorithm>
#include <cmath>
#include <iostream>

typedef long long ll;
ll w[500005];  // 存储每件衣服的湿度
int n, a, b;   // n: 衣服数量, a: 自然晒干速度, b: 烘干机额外烘干速度

// 检查函数:判断是否能在 mid 秒内晒干所有衣服
bool check(ll mid) {
    ll total_time = mid;  // 剩余可用的烘干机时间,初始为 mid 秒
    for (int i = 1; i <= n; i++) {
        // 如果这件衣服在 mid 秒内自然晒干就能干,则不需要烘干机
        if (w[i] <= mid * a) {
            continue;
        }

        // 计算扣除自然晒干 mid*a 后,还剩下的湿度
        ll need = w[i] - mid * a;

        // 剪枝:如果剩下的湿度连用满 mid 秒烘干机都干不了,直接返回不可行
        // 注意:这里不是必须的,但可以加速。烘干机每秒额外提供 b 点湿度消除
        if (need > mid * b) {
            return false;
        }

        // 计算需要烘干机多少秒才能消除剩余的 need 湿度
        // 使用整数向上取整公式 (need + b - 1) / b
        // 因为烘干机每秒额外贡献 b,加上原本的 a,总共是 a+b。
        // 这里只计算额外部分需要的时间,因为自然部分 mid*a 已经统一减去了。
        // 实际上,衣服 i 需要 t_i 时间烘干,mid - t_i 时间自然晒。
        // 总去湿 = t_i * (a+b) + (mid - t_i) * a = t_i * b + mid * a
        // 所以需要满足:t_i * b + mid * a >= w[i]
        // 也就是 t_i * b >= w[i] - mid * a
        // 即 t_i >= (w[i] - mid * a) / b
        ll time = (need + b - 1) / b;

        // 如果这件衣服需要的烘干时间超过了剩余可用时间,则 mid 秒不可行
        if (time > total_time) {
            return false;
        }

        // 扣除这件衣服占用的烘干机时间
        total_time -= time;
    }
    return true;  // 所有衣服都能在 mid 秒内干,且烘干机时间够分配
}

int main() {
    std::cin >> n >> a >> b;
    ll r = 0;  // 二分查找的上界
    for (int i = 1; i <= n; i++) {
        std::cin >> w[i];
        r = std::max(r, w[i]);  // 最坏情况:衣服全是自然晒干,需要 max(w[i]) /
                                // a 时间,粗略取 max(w[i]) 即可
    }

    ll l = 1;  // 二分查找的下界
    while (l <= r) {
        ll mid = l + (r - l) / 2;
        if (check(mid)) {
            // 如果 mid 秒可行,说明答案可能是 mid 或者更小
            r = mid - 1;
        } else {
            // 如果 mid 秒不可行,说明需要更多时间
            l = mid + 1;
        }
    }

    std::cout << l << std::endl;
    return 0;
}

所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

GESP 学习专题站:GESP WIKI

luogu-”系列题目可在洛谷题库进行在线评测。

bcqm-”系列题目可在编程启蒙题库进行在线评测。

欢迎加入Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答

欢迎加入C++ GESP/CSP认证学习QQ频道,考试资源总结汇总

欢迎加入C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
本文由作者按照 CC BY-NC-SA 4.0 进行授权