HDU 6000 Wash (双二分+贪心)

Wash

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 64000/64000 K (Java/Others)
Total Submission(s): 2613    Accepted Submission(s): 700


 

Problem Description

Mr.Panda is about to engage in his favourite activity doing laundry! He’s brought L indistinguishable loads of laundry to his local laundromat, which has N washing machines and M dryers.The ith washing machine takes Wi minutes to wash one load of laundry, and the ith dryer takes Di minutes to dry a load of laundry.
At any point in time, each machine may only be processing at most one load of laundry.
As one might expect, Panda wants to wash and then dry each of his L loads of laundry. Each load of laundry will go through the following steps in order:
1. A non-negative amount of time after Panda arrives at the laundromat, Panda places the load in an unoccupied washing machine i.
2. Wi minutes later, he removes the load from the washing machine, placing it in a temporary holding basket (which has unlimited space)
3. A non-negative amount of time later, he places the load in an unoccupied dryer j 
4. Dj minutes later, he removes the load from the dryer Panda can instantaneously add laundry to or remove laundry from a machine. Help Panda minimize the amount of time (in minutes after he arrives at the laundromat) after which he can be done washing and drying all L loads of laundry!

 

 

Input

The first line of the input gives the number of test cases, T.
T test cases follow. Each test case consists of three lines. The first line contains three integer L, N, and M.
The second line contains N integers W1,W2,...,WN representing the wash time of each wash machine.
The third line contains M integers D1,D2,...,DM representing the dry time of each dryer.

 

 

Output

For each test case, output one line containing “Case #x: y”, where x is the test case number (starting from 1) and y is the minimum time it will take Panda to finish his laundry.

limits


∙1≤T≤100.
∙1≤L≤106.
∙1≤N,M≤105.
∙1≤Wi,Di≤109.

 

 

Sample Input

 

2 1 1 1 1200 34 2 3 2 100 10 1 10 10

 

 

Sample Output

 

Case #1: 1234 Case #2: 12

题意:

给你n(n<=1e6)件衣服,m(m<=1e5)台洗衣机,n(n<=1e5)台烘干机。每台洗衣机有洗一件衣服的时间a[i],每台烘干机有烘干一件衣服的时间b[j],问你最快多长时间洗完n件衣服。时限10000ms

思路:

网上题解给的全都是优先队列+贪心的做法,然而这种做法效率比较低,为8000~10000ms之间,因此这里我给出一种效率极好,代码比较短,又好理解,时间仅需5000ms左右的双二分+贪心的算法。目前我的代码已经在vj上效率排第一。

贪心的思想还是一样,求出每件衣服的洗完时间和烘干时间之后,用洗衣服最短时间的和烘干最长时间的匹配,次短和次长匹配,自己画一画,想一想,这样肯定是最优的。但是求最短多长时间洗完、烘干n件衣服的时间,网上都说用优先队列求的。

然而其实提高结束时间,所有洗衣机洗完的衣服数量一定是单调递增的。所以满足二分的性质。

因此代码变得极简单:二分求出最早的能洗完n件衣服的结束时间,再二分求出最早的能烘干n件衣服的结束时间。再求出每件衣服的洗完、烘干时间,进行一一贪心匹配取最大值即可。思想很简单,代码也很好写。

注意:统计每件衣服的洗完、烘干时间的数组要开大一些,因为二分结果可能洗、烘干多余的衣服,我们只取前n小的即可。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 10000000000000000LL
using namespace std;
const int maxn=100010;
ll n,m,k;
ll a[maxn],b[maxn];
ll c[10000010],d[10000010],now;
bool jud(ll x)
{
    ll sum=0;
    for(ll i=0;i<m&&(x>=a[i]);i++)
    {
        sum+=(x/a[i]);
        if(sum>=n) return 1;
    }
    return 0;
}
bool judd(ll x)
{
    ll sum=0;
    for(ll i=0;i<k&&(x>=b[i]);i++)
    {
        sum+=(x/b[i]);
        if(sum>=n) return 1;
    }
    return 0;
}
ll go()
{
    ll l=0,r=inf;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        if(jud(mid)) r=mid;
        else l=mid+1;
    }
    ll cnt=0;
    for(ll i=0;i<m;i++)
    {
        ll num=r/a[i],kk=1;
        while(num)
        {
            c[++cnt]=a[i]*kk;
            kk++;
            num--;
        }
    }
    sort(c+1,c+cnt+1);
    l=0,r=inf;
    while(l<r)
    {
        ll mid=(l+r)>>1;
        if(judd(mid)) r=mid;
        else l=mid+1;
    }
    cnt=0;
    for(ll i=0;i<k;i++)
    {
        ll num=r/b[i],kk=1;
        while(num)
        {
            d[++cnt]=b[i]*kk;
            kk++;
            num--;
        }
    }
    sort(d+1,d+cnt+1);
    ll ans=c[1]+d[1];
    for(ll i=1;i<=n;i++)
    {
        ans=max(ans,c[i]+d[n-i+1]);
    }
    return ans;
}
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        for(int i=0;i<m;i++)
        scanf("%lld",&a[i]);
        for(int i=0;i<k;i++)
        scanf("%lld",&b[i]);
        sort(a,a+m);
        sort(b,b+k);
        printf("Case #%d: %lld\n",cas++,go());
    }
    return 0;
}
/*
2
1 1 1
1200
34
2 3 2
100 10 1
10 10
*/

附:效率截图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值