题意
传送门 POJ 2010
谈谈二分
这道题有个二分的操作,很好奇单调性如何解决,看了看评论里面的代码,基本思路是对分数排序后二分,然后从排序的花费里面取搜索的中位数左右两侧的最小值,判断是否为可行解来收缩上下界。Emmmmm…问题是对于搜索到的某个中位数而言,这个数对应的花费是必须要取到的,然后就没有然后了,没有单调性。
优先队列
按照分数对牛排序,用优先队列从左向右扫描维护当前所处理牛左侧 头牛的最小和;同理求右侧最小和。枚举中位数,满足 的最大值即答案。
#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;
}