1 条题解

  • 2
    @ 2025-12-3 21:24:13

    一、思路分析

    1. 核心问题拆解

    • 自然晒干:所有衣服同时进行,每秒每件衣服减少 a 点湿度(无额外成本)。
    • 烘衣机烘干:同一时间只能烘1件,每秒让当前衣服额外减少 b 点湿度(总减少 a+b 点),本质是「串行补充烘干」。
    • 目标:找到最小时间 t,使得所有衣服的湿度在 t 秒内降至0。

    2. 关键观察(二分答案的合理性)

    • 单调性:若时间 t 能烘干所有衣服,则任何 t' > t 一定也能(时间越充裕,越容易完成)。
    • 二分性:存在最小的 t_min,使得 t >= t_min 时都能完成,t < t_min 时无法完成。因此可通过「二分查找」高效找到 t_min

    3. 校验函数 check(t) 设计(核心逻辑)

    给定时间 t,判断能否烘干所有衣服:

    1. 对每件衣服,先计算「自然晒干的最大湿度减少量」:t * a
    2. 若衣服湿度 w[i] <= t*a:无需烘衣机,自然晒干即可,跳过。
    3. w[i] > t*a:需要烘衣机补充烘干,所需烘衣时间为 (w[i] - t*a + b - 1) / b(向上取整公式,避免浮点数运算)。
    4. 累加所有衣服的烘衣时间总和:若总和 <= t,说明烘衣机在 t 秒内可串行处理完所有需求,返回 true;否则返回 false

    4. 二分查找边界

    • 左边界 l:最小可能时间(初始为1)。
    • 右边界 r:最大可能时间(因 w[i] <= 5e5a >=1,最坏情况无需烘衣机时,最大时间为 5e5,故设 r=5e5+10 足够覆盖所有情况)。

    二、带详细注释的代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 5e5 + 10;  // 数组最大容量,适配数据范围(n<=5e5)
    int n, a, b;             // n:衣服件数;a:自然晒干速率;b:烘衣机额外烘干速率
    int w[N];                // 存储每件衣服的初始湿度
    
    // 校验函数:判断时间x是否能烘干所有衣服
    bool check(int x) {
        int total_dryer_time = 0;  // 所有衣服所需的总烘衣机时间(串行)
        for (int i = 1; i <= n; ++i) {
            // 1. 计算自然晒干x秒后的剩余湿度:若<=0,无需烘衣
            int natural_dry = x * a;
            if (w[i] <= natural_dry) {
                continue;
            }
            // 2. 需烘衣机处理的湿度:总湿度 - 自然晒干的湿度
            int need_dry = w[i] - natural_dry;
            // 3. 计算该衣服所需烘衣时间(向上取整:(x+y-1)/y 等价于 ceil(x/y))
            int dryer_time = (need_dry + b - 1) / b;
            // 4. 累加总烘衣时间,若超过x秒,直接返回false(烘衣机忙不过来)
            total_dryer_time += dryer_time;
            if (total_dryer_time > x) {
                return false;
            }
        }
        // 所有衣服的总烘衣时间 <= x,x秒足够
        return true;
    }
    
    int main() {
        // 读入输入数据
        cin >> n >> a >> b;
        for (int i = 1; i <= n; ++i) {
            cin >> w[i];
        }
    
        int l = 1;                  // 二分左边界:最小可能时间
        int r = 5e5 + 10;           // 二分右边界:最大可能时间(覆盖所有情况)
        int ans;                    // 存储最终答案(最小时间)
    
        // 二分查找核心循环
        while (l <= r) {
            int mid = l + r >> 1;   // 计算中间时间(等价于 (l+r)/2,避免溢出)
            if (check(mid)) {       // 若mid秒足够,尝试找更小的时间
                ans = mid;          // 记录当前有效时间
                r = mid - 1;        // 向左收缩查找范围
            } else {                // 若mid秒不够,需要更长时间
                l = mid + 1;        // 向右收缩查找范围
            }
        }
    
        // 输出最小时间
        cout << ans << endl;
        return 0;
    }
    

    三、代码关键细节解释

    1. 向上取整公式(need_dry + b - 1) / b
      例:need_dry=3,b=2(3+2-1)/2=4/2=2(正确,需2秒);need_dry=4,b=2(4+2-1)/2=5/2=2(正确,需2秒)。避免使用浮点数 ceil(),提升效率。

    2. 二分查找效率
      二分查找的次数为 log2(5e5) ≈ 19 次,每次 check 函数遍历 n 件衣服(O(n)),总时间复杂度 O(n log M)M 为最大可能时间),适配 n=5e5 的数据范围,不会超时。

    3. 边界处理
      右边界设为 5e5+10 是因为:当 a=1w[i]=5e5 时,仅自然晒干就需要 5e5 秒,加10是为了避免极端情况溢出。

    4. 样例验证
      样例输入:3 2 1w=[1,3,4]

      • 检查 t=2:自然晒干 2*2=4 点湿度。
        • 1≤4 → 无需烘衣;3≤4 → 无需烘衣;4≤4 → 无需烘衣。总烘衣时间=0≤2 → check(2)=true
      • 检查 t=1:自然晒干 2*1=2 点湿度。
        • 4>2,需烘衣 4-2=2 点,烘衣时间=2秒,总烘衣时间=2>1 → check(1)=false
          故最小时间为2,与样例输出一致。
    • 1

    信息

    ID
    1231
    时间
    1000ms
    内存
    128MiB
    难度
    7
    标签
    (无)
    递交数
    380
    已通过
    83
    上传者