bzoj5088 wash

题目大意

\(n\)个洗衣机,每次只能洗一件衣服,分别需要\(a_1,a_2,...a_n\)分钟;\(m\)个烘干机,每次只能烘干一件衣服,分别需要\(b_1,b_2,...b_m\)分钟。要洗并烘干\(l\)件衣服,问最少需要的时间。

题解

考虑只用洗衣服,相当于一开始\(x_i=1\),每次选一个\(i\)\(ans=max\{ ans,x_i*a_i\}\)\(++x_i\)
显然每次选最小的,否则交换后更优。用堆维护一下就行了。
这样我们可以预处理出每件衣服在什么时候洗好。

考虑一个烘干机,它需要的时间为\(b\)\(c_1,c_2,...c_n\)这些时间都有一件洗完的衣服送过来。
显然是送几件衣服马上烘干,让烘干机能工作就工作,这样第一件衣服时间为\(c_1+b\),第二件为\(max\{ c_1+2*b,c_2+b\}\),...,第\(n\)件为\(max\{c_1+n*b,c_2+(n-1)*b,...,c_{n-1}+2*b,c_n+b\}\)
按时间从晚到早考虑就是每件衣服用一个烘干机,烘干机用第\(x\)次代价为\(x*b\),加上原有洗衣服的时间贡献到答案。

考虑多个烘干机,从晚到早考虑洗好的衣服,每次选一个烘干机。相当于一开始\(x_i=1\),每次选一个\(i\)\(ans=max\{ ans,a+x_i*b_i\}\)\(++x_i\)
这里\(a\)是单调递减的,所以我们要求越小的越靠前,这样就可以像上面那样贪心了。

为什么这个贪心中不会出现“把前面一个扩大一点,后面一个缩小一点,使答案更平均”这种情况呢?我们换一种角度考虑,相当于有\(b_1,2*b_1,...,l*b_1,b_2,2*b_2,...,l*b_2,...b_1,2*b_m,...,l*b_m\)\(l*m\)个数,选出最小的\(l\)个与\(a\)配对,那么我们选出的数都是固定的,最优情况会紧密挨在一起,就不会出现一个扩大一个缩小的情况了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pll;
LL rd(){
    LL x=0,flg=1;
    char c=getchar();
    for (;(c<48||c>57)&&c!='-';c=getchar());
    if (c=='-') flg=-1,c=getchar();
    for (;c>47&&c<58;x=x*10+c-48,c=getchar());
    return flg*x;
}
const int mxn=1000010;
int n,m,k;
LL a[mxn],b[mxn];
priority_queue<pll> q;
int main()
{
    n=rd(),k=rd(),m=rd();
    for (int i=1,x;i<=k;++i)
        x=rd(),q.push(make_pair(-x,x));
    for (int i=1;i<=n;++i){
        pll x=q.top();
        q.pop();
        a[i]=-x.first;
        x.first-=x.second;
        q.push(x);
    }
    for (;!q.empty();q.pop());
    for (int i=1,x;i<=m;++i)
        x=rd(),q.push(make_pair(-x,x));
    LL ans=0;
    for (int i=n;i;--i){
        pll x=q.top();
        q.pop();
        ans=max(ans,a[i]-x.first);
        x.first-=x.second;
        q.push(x);
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2020-01-11 21:34  _lhyyy  阅读(142)  评论(0编辑  收藏  举报