题解 洛谷 P4694 【[PA2013]Raper】

首先考虑题目的性质,不难发现光盘的花费是一个凸函数。当生产 \(0\) 张光盘时,其花费为 \(0\),随着光盘生产数的增加,最优情况肯定是先选择工厂便宜的时刻,所以花费会增长越来越快,因此其为一个下凸的凸函数。

采用 \(WQS\) 二分来优化掉生产出 \(k\) 张光盘的限制,然后可以通过二分图带权匹配来判定。每个 \(b\) 向其之前所有的 \(a\) 连边,表示可以进行匹配来生产光盘,当匹配的权值为正时就停止匹配,用匹配数来判定二分。

但是这样复杂度无法接受,于是采用模拟费用流的方法,用一个小根堆来实现反悔操作,堆中为 \(a\) 的权值,每次 \(b\) 和最小的 \(a\) 进行匹配。但是这样匹配不一定是最优,因此就像费用流一样,将 \(b\) 的权值取负再加入堆中,表示可以有别的 \(b\) 来代替它。

判定时二分的权值加在 \(b\) 上,和 \(b\) 一同取负即可,同时还需注意每次匹配是产生新匹配还是代替之前的匹配。

\(code:\)

#include<bits/stdc++.h>
#define maxn 500010
#define inf 10000000000
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
ll n,k,ans,cnt,sum,l=-inf,r=inf;
ll a[maxn],b[maxn];
struct node
{
    ll val;
    bool tag;
};
bool operator <(const node &a,const node &b)
{
    return a.val>b.val;
}
bool check(ll x)
{
    priority_queue<node> q;
    cnt=sum=0;
    for(int i=1;i<=n;++i)
    {
        q.push((node){a[i],0});
        if(q.top().val+b[i]+x<=0)
        {
            sum+=q.top().val+b[i]+x;
            if(!q.top().tag) cnt++;
            q.pop(),q.push((node){-b[i]-x,1});
        }
    }
    return cnt>=k;
}
int main()
{
    read(n),read(k);
    for(int i=1;i<=n;++i) read(a[i]);
    for(int i=1;i<=n;++i) read(b[i]);
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    check(ans),printf("%lld",sum-ans*k);
    return 0;
}
posted @ 2020-07-18 15:09  lhm_liu  阅读(285)  评论(0编辑  收藏  举报