Preparing for the Contest

时间:2021-03-17 19:04:31
 Codeforces Round #222 (Div. 1)B:http://codeforces.com/contest/377/problem/B
题意:m个任务,每个任务会有一个复杂度,然后给你n个人,每个人会有一个能力值,一个任务只有被能力值不少于它的人所完成。并且每个人完成任务会有一个费用,这个费用是固定,不论完成多少任务,只要付一次,一个任务只由一个人完成,一个人可以完成多个任务,但是每个人每天只能完成一个任务,现在给以一个总的费用,让你找出在不超过总费用的情况下,去完成这m个任务,并且要求时间短。
题解:想到了贪心,但是没想到要二分天数。最多需要m天去完成,这是显然的,这是在能够完成的前提下。还是那句话,二分一定要有线性关系,这里的线性关系就是,天数越多,任务被完成的可能性越大。对于t天来说,对于任务中复杂度最高的那个任务来说,应该找一个能力水平不小于它,并且费用最少的那个人来完成,这样的费用一定是最少的,那个人花了1天完成了那个任务之后,对于其他任务来说,它肯定是可以完成的,而且他完成后面的任务都是不需要费用的,所以再让他完成t-1个任务。只花了一个任务钱,对于前面的任务来说,要想完成,又要找一个人,让他来完成,重复上面的,直到所有的任务都被完成。实现的时候,可以用一个优先队列来存,然后任务按复杂度从小到大的顺序排序,人按照能力值从小到大排序。然后每一次选择一个当前最复杂的那个任务,把所有比它大=的人都放进队列,然后选择一个最小,去完成前t个任务,然后不断重复,不断二分,最后得到答案。
 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+;
struct Node{
int val;
int id;
bool operator<(const Node a)const{
return val<a.val;
}
}task[N];
struct Edge{
int b;
int c;
int id;
bool operator<(const Edge a)const{
return b<a.b;
}
}stu[N];
struct result{
int id;
int cost;
bool operator<(const result a)const{
return cost>a.cost;
}
};
int ans[N],temp[N];
int n,m,s;
bool judge(int t){
int len=m,p=n,tp=s;
priority_queue<result>Q;
while(len>=){
while(p>=&&stu[p].b>=task[len].val){
result aaa;
aaa.cost=stu[p].c;
aaa.id=stu[p].id;
Q.push(aaa);
p--;
}
if(Q.size()==)return false;
result ta=Q.top();
Q.pop();
tp-=ta.cost;
if(tp<)return false;
for(int i=max(,len-t);i<=len;i++)
ans[task[i].id]=ta.id;
len-=t;
}
for(int i=;i<=m;i++)
temp[i]=ans[i];
return true;
}
int main(){
while(~scanf("%d%d%d",&n,&m,&s)){
for(int i=;i<=m;i++){
scanf("%d",&task[i].val);
task[i].id=i;
}
for(int i=;i<=n;i++)
scanf("%d",&stu[i].b);
for(int i=;i<=n;i++){
scanf("%d",&stu[i].c);
stu[i].id=i;
}
sort(task+,task+m+);
sort(stu+,stu+n+);
int minn=-,l=,r=m;
while(l<=r){
int mid=(l+r)/;
if(judge(mid)){
r=mid-;
minn=mid;
}
else l=mid+;
}
if(minn==-)printf("NO\n");
else{
printf("YES\n");
for(int i=;i<=m;i++){
printf("%d ",temp[i]);
}
printf("\n");
}
}
}