POJ 3104 Drying (二分)

本文探讨了通过二分查找法解决衣物干燥问题的方法。针对衣物的自然干燥和使用烘干机加速干燥两种方式,提出了有效的算法策略。文章还特别注意到了数据类型的选择,确保在大数值运算中的准确性。

题意:我要把一些衣服弄干,已知每件衣服的含水量,如果让他们自然干,没小时少1单位水,如果用烘干机,每小时少k单位水,但烘干机没小时只能放一件衣服。


思路:我一开始是用贪心做的,TLE(每次取含水量最多的衣服放进烘干机一小时,再取含水量最多的衣服,重复操作直到含水量最多的衣服含水量为0)。看了网上的题解才知道,应该用二分法找最短时间。其中在烘干时,每小时减少的水量中k-1视为烘干机的效果,仍然有1为自然干。则对于含水量大于 t 的衣服,其中t为自然干,烘干的部分为a[i] - t,是烘干机作用 ( a[i] - t + (k - 1) - 1 ) / (k - 1) 小时的效果(a / b取上界等于(a + b - 1) / b)。用sum记录烘干机作用时间之和,最短时间 t 应满足, t >= sum。所以用二分法求第一个满足该条件的 t 值(二分法取下界)。


另外要注意数据范围

unsigned   int  和 unsigned long   约为 0~4* 10 ^ 9   

int  和 long 绝对值约为 2 * 10 ^ 9 

long long 绝对值约为 9* 10 ^ 18
unsigned long long的最大值:约为 0 ~ 18 * 10 ^ 18

此题应用long long


#include 
#include 
using namespace std;

int main()
{
    #ifdef LOCAL
    freopen("data.in", "r", stdin);
    #endif

    int n, i;
    long long  l, r, mid, sum, ans;
    long long a[100010], k;
    while(scanf("%d", &n) != EOF)
    {
        for(i = 0; i < n; i++)
        {
            scanf("%lld", &a[i]);
        }
        scanf("%lld", &k);
        sort(a, a + n);
        if(k == 1)
        {
            printf("%lld\n", a[n -1]);
            continue;
        }
        l = 1; r = a[n - 1]; ans = 0;
        while(l <= r)
        {
            sum = 0;
            mid = (l + r) / 2;
            for(int i = n - 1; i >= 0; i-- )
            {   if(a[i] > mid)
                {
                    sum += (a[i] - mid + k - 2) / (k - 1);
                }
                else break;
            }
            //注意二分查找去下界的写法
            if(sum <= mid)
            {
                r = mid - 1;
            }
            else
            {
                l = mid + 1;
            }
        }
        printf("%lld\n", l);
    }
    return 0;
}

<think>嗯,用户问的是POJ3104用C++怎么写。首先我得回忆一下这道题的内容。POJ3104应该是一个算法题,可能涉及到二分查找或者贪心策略。不过具体的题目内容我得先确认一下。 POJ3104的题目大意是说,有n件衣服,每件衣服有ai滴水。现在用烘干机来烘干,每分钟可以选择一件衣服用烘干机,这样能烘干k滴水,而自然晾干每分钟只能烘干1滴。但烘干机一次只能处理一件衣服,其他衣服在那一分钟只能自然晾干。问最少需要多少分钟才能把所有衣服烘干。对吧? 那这个问题正确的解法应该是用二分查找。因为我们需要找到最小的分钟数,假设这个分钟数是mid。对于每件衣服,如果ai <= mid,那自然晾干就行。但如果ai > mid,就需要使用烘干机。这时候,计算用烘干机的次数x,满足ai - x*k <= mid -x,因为每次烘干机使用会多减少(k-1)滴水。所以x >= (ai - mid)/(k-1)。这里需要注意除法向上取整的问题。然后将所有需要的x加起来,如果总和超过mid,则mid太小,需要增大下界,反之可以尝试缩小上界。 不过这里有个特殊情况,当k=1的时候,因为k-1=0,这时候烘干机和自然晾干的效果一样,所以只能自然晾干,所需时间就是最大ai的值。 接下来,如何用C++实现呢?首先读取n,然后读取每个ai,接着读取k。然后进行二分查找。左边界是1,右边界是最大的ai。每次计算mid,然后判断是否可行。需要注意的是,当k=1的时候要独处理,否则计算的时候会出现除以0的情况。 可能的代码结构大致如下: 读取输入,保存到数组a中。 计算最大的ai作为初始右边界。 如果k=1,直接输出max_ai。 否则,进行二分查找: left = 1, right = max_ai while left < right: mid = (left + right) / 2 计算总需要的烘干次数sum for每个ai: if ai > mid: sum += ceil((ai - mid) / (k - 1)) if sum <= mid: right = mid else: left = mid + 1 输出left 这里需要注意的是,计算(ai - mid)的时候,如果这个值是负数的话不需要处理。另外,ceil可以用整数运算来实现,例如 (ai - mid + k - 2) / (k -1)。 测试一下边界情况,比如当k=1的时候是否正确。另外,当所有ai都不需要烘干机的情况,比如所有ai都<=mid,这时候sum是0,所以可以满足。 还有可能出现的问题是在计算sum的时候,可能会溢出,但题目中的数据范围可能不会太大,所以用long long可能更安全。不过POJ的数据范围可能需要看题目具体要求。假设ai的范围在1e9的话,用long long更合适。 所以代码中变量sum应该用long long类型,防止累加时溢出。 综上,C++代码的大体框架应该是这样的。需要处理k=1的特殊情况,二分查找的条件判断,以及计算烘干次数时的向上取整。</think>POJ3104 题目要求用高效方法烘干衣服,下面详细介绍解题思路和C++实现: ### 题目分析 **问题描述**: - $n$件衣服,每件初始含水量为$a_i$ - 每分钟可选择**1件**衣服用烘干机(每秒减少$k$滴水),其余衣服自然晾干(每秒减少$1$滴) - 求烘干所有衣服的**最短时间** **关键观察**: 1. 烘干机使用策略影响总时间 2. 直接模拟会超时,需用**二分法**优化时间复杂度 ### 算法思路 1. **二分查找答案**: - 最小时间范围:$left=1$, $right=\text{max}(a_i)$ - 对每个候选时间$mid$,检查是否可行 2. **可行性判断**: - 对每件衣服$a_i$: - 若$a_i \leq mid$:自然晾干即可 - 若$a_i > mid$:需使用烘干机,计算最少使用次数 $$\text{烘干次数} \geq \lceil \frac{a_i - mid}{k-1} \rceil$$ - 总烘干次数$\leq mid$时才合法(每分钟最多用1次烘干机) ### C++代码实现 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; typedef long long ll; int main() { int n, k; cin >> n; vector<int> a(n); for(int i=0; i<n; ++i) cin >> a[i]; cin >> k; int max_a = *max_element(a.begin(), a.end()); if(k == 1) { // 特殊情况处理 cout << max_a << endl; return 0; } ll left = 1, right = max_a; while(left < right) { ll mid = (left + right) / 2; ll sum = 0; for(int ai : a) { if(ai > mid) { // 计算ceil((ai - mid)/(k-1)) sum += (ai - mid + k-2) / (k-1); if(sum > mid) break; // 提前终止 } } if(sum <= mid) right = mid; else left = mid + 1; } cout << left << endl; return 0; } ``` ### 代码解析 1. **输入处理**:读取衣服数量和含水量 2. **特判$k=1$**:此时烘干机无效,直接输出最大含水量 3. **二分框架**: - 每次计算中点$mid$ - 统计所需烘干机总次数 - 根据总次数调整搜索区间 4. **关键计算**: - 使用整数技巧实现向上取整,避免浮点误差 - 提前终止循环优化效率 ### 复杂度分析 - **时间复杂度**:$O(n \log C)$,其中$C$为最大含水量 - **空间复杂度**:$O(n)$存储含水量数据 此解法能够高效处理题目中的大规模数据,通过二分将问题转化为可行性验证,避免了直接模拟的低效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值