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% 的数据,有 1≤n,m≤500 000;1≤o≤min(n,m);1≤ci,pi,vi,di≤109,保证 ∀1≤i,j≤n,若pi<pj,则ci≤cj。
分析:
很容易想到的贪心,优先选择价值大且人数少的订单,对于每一个订单又优先选择容量小且花费小的房间。
所以先对房间和订单排序,房间按照容量与花费排序,订单按价值和人数排序。然后二分查找找到一个人数足够花费最小的房间,记录得到的收益,然后对所有收益排序取最大的$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<<' '; //for(int i=1; i<=m; ++i) cout<<b[i].val<<' '<<b[i].num<<' '; 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 ",ans); return 0; }