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
", Ans);
return 0;
}
/*
4 100
5 1000
10 100
8 10
20 1
2
*/