Evanyou Blog 彩带

洛谷P4698 [CEOI2011]Hotel [贪心,二分,并查集]

  题目传送门

Hotel

题目描述

你经营着一家旅馆,这家旅馆有 n 个房间,每个房间有维护费用和容量。其中第 i 个房间的维护费用为 ci,容量为 pi 人。

现在有 m 个订单,每个订单有两个参数:vi,di ,其中 vi 表示这个订单支付的租金,di​​ 表示人数。

你现在得要合理选择一些订单,并放弃其他订单,使得每个选择的订单被安排在同一间房间内,且人数不超过这个房间的容量限制。当然,两个不同的订单也不能被安排在同一间房间内。

现在你想要知道,在最多选出o 个订单时的最大收益。一个方案的收益的定义为,选出的订单的租金和,减去选出的房间的维护费用和。

输入格式

第一行三个空格隔开的整数n,m,o 。

接下来 n 行,每行两个空格隔开的整数 ci,pi

接下来 m 行,每行两个空格隔开的整数 vi,di

输出格式

一行一个整数表示最大收益。注意答案可能很大。

输入输出样例

输入

3 2 2
150 2
400 3
100 2
200 1
700 3
输出 
400

说明/提示

样例 11 解释

可以将第一个订单安排至第三个房间,将第二个订单安排至第二个房间。

数据范围

对于 100% 的数据,有 1n,m500 000;1omin(n,m);1ci,pi,vi,di109,保证 1i,jn,若pi<pj,则cicj

 


  分析:

  很容易想到的贪心,优先选择价值大且人数少的订单,对于每一个订单又优先选择容量小且花费小的房间。

  所以先对房间和订单排序,房间按照容量与花费排序,订单按价值和人数排序。然后二分查找找到一个人数足够花费最小的房间,记录得到的收益,然后对所有收益排序取最大的$o$个。

  但问题在于一个房间可能已经被之前的订单占用了,所以用并查集维护一下,如果一个房间$x$被使用了,就令$fa[x]$等于$x-1$,因为显然这样是最优的。当然注意一下当搜到的房间的$fa$为$0$时不能记录。

  Code:

 

//It is made by HolseLee on 11th Aug 2019
//Luogu.org P4698
#include<bits/stdc++.h>
using namespace std;

const int N=5e5+7;
int n,m,o,fa[N],mon[N];
long long ans;
struct Room {
    int cos,p;
    bool operator < ( const Room A ) const {
        return p==A.p ? cos>A.cos : p>A.p; 
    }
}a[N];
struct Custom {
    int val,num;
    bool operator < ( const Custom A ) const {
        return val==A.val ? num<A.num : val>A.val;
    }
}b[N];

inline int read()
{
    int x=0; char ch=getchar();
    while( ch<'0' || ch>'9' ) ch=getchar();
    while( ch>='0' && ch<='9' ) {
        x=x*10+ch-'0'; ch=getchar();
    }
    return x;
}

int search(int v)
{
    int l=1, r=n, mid, ret=0;
    while( l<=r ) {
        mid=l+r>>1;
        if( a[mid].p>=v ) ret=mid, l=mid+1;
        else r=mid-1;
    }
    return ret;
}

int find(int x)
{
    return fa[x]==x ? x : fa[x]=find(fa[x]);
}

int main()
{
    n=read(), m=read(), o=read();
    for(int i=1; i<=n; ++i) {
        a[i].cos=read(), a[i].p=read(); fa[i]=i;
    }
    for(int i=1; i<=m; ++i) {
        b[i].val=read(), b[i].num=read();
    }
    sort(a+1,a+n+1); sort(b+1,b+m+1);
    //for(int i=1; i<=n; ++i) cout<<a[i].cos<<' '<<a[i].p<<'\n';
    //for(int i=1; i<=m; ++i) cout<<b[i].val<<' '<<b[i].num<<'\n';
    int x,tot=0,sum=0;
    for(int i=1; i<=m; ++i) {
        x=search(b[i].num);
        x=find(x);
        if( x ) {
            if( b[i].val-a[x].cos<=0 ) continue;
            mon[++tot]=(b[i].val-a[x].cos);
            fa[x]=x-1;
        }
    }
    sort(mon+1,mon+tot+1);
    for(int i=tot; i>0; --i) {
        ans+=mon[i]; sum++;
        if( sum==o ) break;
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2019-08-11 21:59  HolseLee  阅读(334)  评论(0编辑  收藏  举报