手机没电了没带充电器怎么办?
题意:
有m个任务,每个任务有两个参数x,y,有n个机器,每个机器有两个参数x,y,当机器的x和y分别大于某任务的x,y时,机器可以完成该项任务。每个机器只能做一个任务,完成一项任务可以获得价值500*x+2*y。求一种分配方案,使得完成的任务数最多,如果有多种方案,求获得价值最大的那一个。
The first line contains two integers N and M. N is the number of the machines.M is the number of tasks(1 < =N <= 100000,1<=M<=100000).
The following N lines each contains two integers xi(0<xi<1440),yi(0=<yi<=100).xi is the maximum time the machine can work.yi is the level of the machine.
The following M lines each contains two integers xi(0<xi<1440),yi(0=<yi<=100).xi is the time we need to complete the task.yi is the level of the task.
1 2 100 3 100 2 100 1
1 50004
比赛的时候这题是我做的。。。。然后做法完全不对。。。。这个题有贪心策略,我没发现。。。。。。
观察x和y的数据范围可以发现,两个任务y的最大差是100,而价值的表达式为500*x+2*y,y造成的差别最大是200,x造成的最小差别(除了相等的情况)是500,因此如果x不一样,肯定是x大的任务价值大,即任务价值可以按先x后y的方法排序。这个性质在后面会用到一丢丢。
第一步贪心,我们按价值排序,从价值大的任务开始分配机器。对这个贪心,我们有两个猜想:
1. 这样分配价值肯定会最大
2. 这样分配完成任务数不会因为这个贪心受影响(这么说是因为之后的贪心也会影响任务数)
先证第二点,如果不从价值大的开始排序,意味着存在价值较大且可以完成的任务t1,不选择它我们可以完成价值较小的任务t2, t3, ...,这显然不可能,t1只跟完成它的机器有关,不做t1造成的影响只是空出一台机器,一台机器只能做一个任务,因此无法增加任务。
这样就好证第一点了,既然完成任务数不变(之后选择机器的贪心策略相同的情况下),选择价值更大的机器就能满足题目第二条要求。
第二部贪心,我们循环每一个任务,对于所有“价值”大于等于当前任务的机器,我们选择y大于等于当前机器y中最小的那个机器来做这个任务(lower_bound操作)。
这步贪心要用到之前的性质,价值大于等于当前任务的机器,它的x值必然大于等于当前任务,然后我们再找出其中y满足条件的所有机器,选取其中最小的。
对于y为什么选最小的:
因为我们按照价值从大到小的顺序处理任务,即按x从大到小的顺序,因此后面要处理的任务x必然比当前任务x要小,所以当前选出的可以完成任务机器的集合里的所有机器在x上都可以胜任,但是y不一定,所以要选择y尽可能小的,把y大的机器留给后面的任务。
实现上来说,建结构体存任务和机器,重载小于号按价值或者x大小。sort排序任务和机器,任务从大到小循环,用一个map<int,int>维护比当前任务价值大的机器,对每个任务lower_bound找y>=任务y的最小机器,处理结果从map中删除。
语法上来说我才知道map<int,int>原来不存在的key对应的value好像默认会是0。。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<map>
using namespace std;
#define mxn 100010
#define mxm 100010
struct item{
int x,y;
bool operator < (const item& in)const{
return 500*x+2*y>500*in.x+2*in.y;
}
long long value(){
return 500*x+2*y;
}
};
item task[mxm],mac[mxn];
int n,m;
map<int,int>mp;
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<n;++i) scanf("%d%d",&mac[i].x,&mac[i].y);
for(int i=0;i<m;++i) scanf("%d%d",&task[i].x,&task[i].y);
sort(mac,mac+n);
sort(task,task+m);
mp.clear();
int now=0;
int cnt=0;
long long ans=0;
map<int,int>::iterator it;
for(int i=0;i<m;++i){
while(now<n&&mac[now].x>=task[i].x)
++mp[mac[now++].y];
it=mp.lower_bound(task[i].y);
if(it!=mp.end()){
ans+=task[i].value();
++cnt;
int tem=it->first;
--mp[tem];
if(!mp[tem]) mp.erase(tem);
}
}
printf("%d %I64d\n",cnt,ans);
}
return 0;
}