CF377B Preparing for the Contest [贪心+优先队列]

题意:

给出n个人的能力值,m个问题的难度值,请n个人需要的花费,花钱的上限s

每个人能解决难度值小于等于他能力值的问题

求出能否在花钱不超过s的情况下把所有问题解决

如果可以输出YES

并输出每个问题由谁来解决的最快的方案

如果不行输出NO


分析:

可以二分枚举天数,因为如果一个任务能x天完成,肯定也能在大于x的天数内完成

如果现在我们是要x天内完成

可以先把任务按复杂程度排序,把人也按复杂度排序

然后对每个任务,找出所有能解决这个问题的人并且把他们压入优先队列(费用低的权大),然后弹出队列里费用最低的, 让这个人解决尽可能多的问题(不超过x个或者就是x个),然后找出紧接着的没有被这个人或前面的人解决的问题,重复上述步骤,继续把能解决它的人压入队列(不要重复压已经压过的),然后弹出队里费用最低的。

如果最后优先队列为空而问题还在,则说明人手不够,不能在x天内完成

否则如果总花费超过s,也是不能在x天内完成

否则可以在x天内完成


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
#define pb push_back
const long long NN=111111;
long long n,m,ss;
long long ans[NN];
struct P{
	long long b,c,id;
	bool operator< (const P another)const{
		return (this->c)>another.c;
	}
}p[NN],a[NN];
bool cmp(P s1,P s2){
	return s1.b<s2.b;
}
priority_queue<P> que;
bool check(long long s){
    memset(ans,0,sizeof(ans));
	while(!que.empty()) que.pop();
	long long qi;
	long long pi=n;
	long long all=0;
	for(qi=m;qi>=1;){
		for(pi=pi;pi>=1;pi--){
			if(p[pi].b>=a[qi].b) que.push(p[pi]);
			else break;
		}
		if(que.empty()) return false;
		P ps=que.top();que.pop();
		all+=ps.c;
		long long cnt=0;
		for(qi=qi;qi>=1;qi--){
			if(ps.b>=a[qi].b){
                    cnt++;
                    ans[a[qi].id]=ps.id;
			}
			else break;
			if(cnt==s){
				qi--;break;
			}
		}
		//if(qi>=1 && pi==0)	   return false;
		if(qi==0 && all>ss)	   return false;
		if(qi==0 && all<=ss)	   return true;
	}
}
int main(){
#ifndef ONLINE_JUDGE
	freopen("G:/in.txt","r",stdin);
	//freopen("G:/myout.txt","w",stdout);
#endif
	cin>>n>>m>>ss;
	for(long long i=1;i<=m;i++)	cin>>a[i].b,a[i].id=i;
	for(long long i=1;i<=n;i++)	cin>>p[i].b;
	for(long long i=1;i<=n;i++)	cin>>p[i].c,p[i].id=i;
	sort(a+1,a+1+m,cmp);
	sort(p+1,p+1+n,cmp);
	long long l=1,r=m,mid=(l+r)/2;
	while(l<r){
		if(check(mid)) 	r=mid;
		else		l=mid+1;
		mid=(l+r)/2;
	}
	if(check(mid)){
        cout<<"YES"<<endl;
        for(long long i=1;i<=m;i++)
            cout<<ans[i]<<' ';
        cout<<endl;
	}else{
        cout<<"NO"<<endl;
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值