CodeForces 377B 优先队列 + 二分

题目

呵呵,这破题目搞了我两个小时,首先题意就有点怕怕的,n个人,具有解决bug的能力,一天只能解决一个,m个bug,bug具有一个难度,只有某个人能力大于等于这个难度才可以解决,请n个人解决一个问题,每个人都要拿钞票的,问不超过s元 的情况下 最快的解决办法

输出每个bug由哪个人解决的方案

先考虑了DP,发现不行,后来就觉得是贪心了,那么就跟优先队列联系上了,把bug的难度 跟人的 解决办法能力都从大到小排,然后开始二分枚举解决天数,假设解决天数为t,那么最厉害的那个人且花费比较合适的那个人最多使用t次,都从大到小排,然后再优先队列一下能解决问题的花费最少的人,每一次更新,若他能解决第一个问题,那么接下里的 t-1个问题他都可以解决,更新是从前往后更新的,所以肯定是最优的,中间花费超过s的方案可以舍去,没办法解决当前未解决的最大难度的bug也要舍去,二分枚举的
最后一个能成功的肯定就是最优的了,

一开始 看看是否最难的bug有人能够解决,否则 输出No

还要看看m天是否有解决方案,因为最多是使用m天,若无法解决那么输出no

接下来才枚举天数

一开始没相当去枚举解决时间,结果弄得很麻烦,后来想到了,敲了,结果中途优先队列有个地方手贱敲错了,一直在调试解决函数,真是醉了。。

int n,m,s;

typedef struct Node {
	int id;
	int nnum;
	bool operator<(const Node &aa)const {
		return nnum > aa.nnum;
	}
};

Node bug[100000 + 55];

typedef struct NODE {
	int id;
	int ablity;
	int cost;
	bool operator<(const NODE & aa)const {
		return cost > aa.cost;
	}
};

NODE stu[100000 + 55];

int maxn;

int ans[100000 + 55],tmp[100000 + 55];

void init() {
	memset(bug,0,sizeof(bug));
	memset(stu,0,sizeof(stu));
}

bool input() {
	while(cin>>n>>m>>s) {
		maxn = -1;
		for(int i=0;i<m;i++) {
			cin>>bug[i].nnum;
			bug[i].id = i + 1;
			maxn = max(maxn,bug[i].nnum);
		}
		for(int i=0;i<n;i++) {
			cin>>stu[i].ablity;
			stu[i].id = i + 1;
		}
		for(int i=0;i<n;i++)cin>>stu[i].cost;
		return false;
	}
	return true;
}

bool cmp(NODE x,NODE y) {
	return x.ablity > y.ablity;
}

bool isok(int t) {
	int ret = 0;
	priority_queue<NODE> q;
	for(int i=0,j=0;i<m;i+=t) {
		for(;j<n;j++) {
			if(stu[j].ablity >= bug[i].nnum)q.push(stu[j]);
			else break;
		}
		if(q.size() == 0)return false;
		NODE qq = q.top();
		q.pop();
		ret += qq.cost;
		if(ret > s)return false;
		int mark = 0;
		for(int j=i;j<m;j++) {
			tmp[bug[j].id] = qq.id;
			mark++;
			if(mark == t)break;
		}
	}
	for(int i=1;i<=m;i++)ans[i] = tmp[i];
	return true;
}

void cal() {
	bool flag = false;
	for(int i=0;i<n;i++) {
		if(stu[i].ablity >= maxn && stu[i].cost <= s)flag = true;
	}
	if(!flag) {puts("NO");return;}
	sort(bug,bug + m);
	sort(stu,stu + n,cmp);
	int cc = 0;
	if(!isok(m)){puts("NO");return ;}
	int l = 1,r = m;
	while(l <= r) {
		int mid = (l + r)>>1;
		if(isok(mid))r = mid - 1;
		else l = mid + 1;
	}
	puts("YES");
	for(int i=1;i<=m;i++)
		printf("%d%c",ans[i],i == m?'\n':' ');
}

void output() {

}

int main() {
	while(true) {
		init();
		if(input())return 0;
		cal();
		output();
	}
	return 0;
}
时间: 2024-10-06 00:58:49

CodeForces 377B 优先队列 + 二分的相关文章

CodeForces 424D: ...(二分)

题意:给出一个n*m的矩阵,内有一些数字.当你从一个方格走到另一个方格时,按这两个方格数字的大小,有(升,平,降)三种费用.你需要在矩阵中找到边长大于2的一个矩形,使得按这个矩形顺时针行走一圈的费用,与给定费用最接近.3<=n,m<=300. 思路:O(1)计算一个矩形的费用不是什么难事,因为考虑到有前缀性质(前缀性质:[l,r] = [0,r] - [0,l-1]),只要预处理好各行各个方向行走的费用,就容易计算. 直接枚举容易得到O(n^4)的算法.难以过.这时就应当想到优化.实际上,经过

Codeforces 460C prsent(二分答案)

//题意:给定N朵花的原先的高度,从左到右排列, //最多浇水m天,每天只能浇一次,每次使得连续的w朵花的高度增长1,问最后最矮的花的高度最高是多少. # include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int main() { __int64 n,m,w,l,r,i,m1,sum; __int64 a[200010],b[200010]; while(~

HDOJ 5371 Hotaru&#39;s problem manacher+优先队列+二分

先用求回文串的Manacher算法,求出以第i个点和第i+1个点为中心的回文串长度,记录到数组c中 比如 10 9 8 8 9 10 10 9 8 我们通过运行Manacher求出第i个点和第i+1个点为中心的回文串长度 0 0 6 0 0 6 0 0 0 两个8为中心,10 9 8 8 9 10是个回文串,长度是6. 两个10为中心,8 9 10 10 9 8是个回文串,长度是6. 要满足题目所要求的内容,需要使得两个相邻的回文串,共享中间的一部分,比如上边的两个字符串,共享 8 9 10这一

CodeForces 371C Hamburgers 二分

CodeForces 371C Hamburgers 二分 题意 给你一个做汉堡包的菜单,他们是由B S C,三种材料做成的,现在我们有一些材料和钱,我们想做最多的汉堡包,请问最多是多少? 解题思路 这里我们开始我们可能会想该怎么买,也就是买的策略是什么,其实我们可以不用去思考这个,理由如下: 假如我们知道最后的结果,我们是不是可以算出来我们要买的东西?答案是肯定的(在钱不浪费的情况下),再加上这个答案是线性单调的,也就是如果答案是m,那么小于m的也是一定可以做到的,这样我们就可以使用二分来枚举

Codeforces 474B Worms (二分查找)

题目链接:Codeforces 474B Worms 题意:给出一串数字比如2 7 3 4 9. 表示第一堆编号是[1,2].第二堆编号是[3,9].第三堆编号是[10,12].第四堆编号是[13,16].第五堆编号是[17,25]. 预处理出每堆的上界二分查找答案. AC代码: </pre><pre name="code" class="cpp">#include<stdio.h> #include<map> #in

CodeForces 359D (数论+二分+ST算法)

题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47319 题目大意:给定一个序列,要求确定一个子序列,①使得该子序列中所有值都能被其中一个值整除,②且子序列范围尽可能大(r-l尽可能大). 解题思路: 对于要求1,不难发现只有min(L,R)=gcd(L,R)时才行.其中gcd是L,R范围内的最大公约数,min是L,R范围内的最小值. 对于要求2,传统思路是r-l从大到小枚举,每次确定一个(L,R)范围,进行判

Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem D (Codeforces 831D) - 贪心 - 二分答案

There are n people and k keys on a straight line. Every person wants to get to the office which is located on the line as well. To do that, he needs to reach some point with a key, take the key and then go to the office. Once a key is taken by somebo

POJ 2010 Moo University - Financial Aid( 优先队列+二分查找)

POJ 2010 Moo University - Financial Aid 题目大意,从C头申请读书的牛中选出N头,这N头牛的需要的额外学费之和不能超过F,并且要使得这N头牛的中位数最大.若不存在,则输出-1(一开始因为没看见这个,wa了几次). 这个题的第一种做法就是用两个优先队列+贪心. /* * Created: 2016年03月27日 14时41分47秒 星期日 * Author: Akrusher * */ #include <cstdio> #include <cstdl

CodeForces - 589A(二分+贪心)

题目链接:http://codeforces.com/problemset/problem/589/F 题目大意:一位美食家进入宴会厅,厨师为客人提供了n道菜.美食家知道时间表:每个菜肴都将供应. 对于第i道菜肴,他知道时间ai和bi的两个整数时刻(从宴会开始的几秒钟内) - ai为该菜端出来的时间,bi为该菜端走的时间(ai <BI).例如,如果ai = 10且bi = 11,那么第i个菜肴可在一秒钟内进食. 菜肴数量非常大,所以只要菜肴可以吃(即,在大厅里),它就无法用完. 美食家想要尝试每