POJ 2010 优先队列

题意

传送门 POJ 2010

谈谈二分

这道题有个二分的操作,很好奇单调性如何解决,看了看评论里面的代码,基本思路是对分数排序后二分,然后从排序的花费里面取搜索的中位数左右两侧的最小值,判断是否为可行解来收缩上下界。Emmmmm…问题是对于搜索到的某个中位数而言,这个数对应的花费是必须要取到的,然后就没有然后了,没有单调性。

优先队列

按照分数对牛排序,用优先队列从左向右扫描维护当前所处理牛左侧 N / 2 N/2 头牛的最小和;同理求右侧最小和。枚举中位数,满足 a i d i F \sum aid_{i} \leq F 的最大值即答案。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#define min(a,b)    (((a) < (b)) ? (a) : (b))
#define max(a,b)    (((a) > (b)) ? (a) : (b))
#define abs(x)    ((x) < 0 ? -(x) : (x))
#define INF 0x3f3f3f3f
#define delta 0.85
#define eps 1e-3
#define PI 3.14159265358979323846
#define MAX_C 100005
using namespace std;
struct calf{
	int scr, aid, ls, rs;
	bool operator < (const calf& other) const{
		return aid < other.aid;
	}
}cf[MAX_C];
int N, C, F;

bool cmp(const calf& a, const calf& b){
	return a.scr < b.scr;
}

int main(){
	while(~scanf("%d%d%d", &N, &C, &F)){
		memset(cf, 0, sizeof(cf));
		for(int i = 0; i < C; i++) scanf("%d%d", &cf[i].scr, &cf[i].aid);
		sort(cf, cf + C, cmp);
		int mid = N / 2;
		int l = mid, r = C - mid, ls = 0, rs = 0;
		priority_queue<int> lq, rq;
		// 求左侧和
		for(int i = 0; i < r; i++){
			int d = cf[i].aid;
			cf[i].ls = ls;
			if(i - l >= 0){
				int d2 = lq.top(); lq.pop();
				ls -= d2 - d > 0 ? d2 - d : 0;
				lq.push(min(d, d2));
			}
			else{
				ls += d;
				lq.push(d);
			}
		}
		// 求右侧和
		for(int i = C - 1; i >= l; i--){
			int d = cf[i].aid;
			cf[i].rs = rs;
			if(r - i > 0){
				int d2 = rq.top(); rq.pop();
				rs -= d2 - d > 0 ? d2 - d : 0;
				rq.push(min(d, d2));
			}
			else{
				rs += d;
				rq.push(d);
			}
		}
		// 枚举中位数 [l, r)
		int res = -1;
		for(int i = r - 1 ; i >= l; i--){
			calf &c = cf[i];
			if(c.aid + c.ls + c.rs <= F){
				res = c.scr;
				break;
			}
		}
		if(res == -1) printf("-1\n");
		else printf("%d\n", res);
	}
	return 0;
}
发布了91 篇原创文章 · 获赞 1 · 访问量 1620

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/105125357