BZOJ 3354 Hiring

BZOJ 3354

考虑枚举Level=1给多少钱
那就是有些人不会来
来的人贪心得从Level最小的开始选
这个贪心正确性显然

哪怎么枚举呢
每个人可以算出给1Level多少钱他才来
对这个值排序,从小到大扫,维护选的人的集合

怎么维护?
对于一个新人能要就要(钱足够)
不能要(钱不够)就看看是不是踢掉已选的Level最大的人
连续踢直至MaxLevel<NewLevel或钱够了

我怎么交了一个I64d还能A?

#include <cstdio>
#include <queue>
#include <algorithm>

using std::sort;
using std::max;
using std::priority_queue;

const int MAXN=500111;

int N;
long long W;
int Ans;

struct Peo{
	long long Lim, Lev;
} P[MAXN];

bool operator < (Peo A, Peo B){
	return A.Lim*B.Lev<B.Lim*A.Lev;
}

long long LevSum;
int Cnt;

priority_queue<long long> PQ;

int main(){
	
	scanf("%d%I64d", &N, &W);
	for(int i=1;i<=N;++i)
		scanf("%I64d%I64d", &P[i].Lim, &P[i].Lev);
	
	sort(P+1, P+N+1);
	
	for(int i=1;i<=N;++i){
		while(!PQ.empty() && PQ.top()>P[i].Lev && (LevSum+P[i].Lev)*P[i].Lim>W*P[i].Lev){
			--Cnt;
			LevSum-=PQ.top();
			PQ.pop();
		}
		if((LevSum+P[i].Lev)*P[i].Lim<=W*P[i].Lev){
			++Cnt;
			LevSum+=P[i].Lev;
			PQ.push(P[i].Lev);
			Ans=max(Ans, Cnt);
		}
	}
	
	printf("%d\n", Ans);
	
	return 0;
}

/*
4 100
5 1000
10 100
8 10
20 1

2

*/

posted @ 2018-09-10 10:54  Pickupwin  阅读(134)  评论(0编辑  收藏  举报