题意很容易理解:Limak可以把自己获得的气球送给别人,使别人的气球大于体重。从而让别人漂浮的天花板上,不能参与排名,从而使Limak自己的排名上升。这个题目是一个典型的贪心,当Limak把自己的气球给别人的时候,他自己的手中的气球就会减少,那么他自己的排名也是有可能降低的。那么,我们就需要思考,Limak应该把气球给什么样的人,他自己的排名才有可能上升。其实,很简单,他肯定是把气球给当前排名在自己前面的人,自己的排名才能上升。那么,问题又来了,他前面的人有很多,到底给哪一个人呢?仔细想一想,他只需要给一个上升至天花板所需要气球最少的即可。Limak每次把气球给别人后,自己的气球数发生了变化,而且也可能会导致一些以前排名在Limak之后的,现在跑到Limak前面。这样以来,每次Limak让一个人上升至天花板后,就需要更新各个选手的排名。那么,关键的问题来了,由于数据量比较大,每次如何快速的找到一个当前排名在Limak前面,且上升至天花板所需的气球最少的选手?我使用了优先队列(重定义小于号,使上升至天花板所需的气球最少的在队首部)保存当前比Limak大的选手即可,这样就能是查找时间为lg(n)。最终的答案为,在处理过程中,队列中的元素最少的时侯,就是Limak排名最靠前的时候。具体的实现如下:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define ll long long
using namespace std;
const int MAX = 300010;
struct Node{
ll t, w, x;
bool operator < (const Node& args) const{
return x > args.x;
}
}a[MAX], b[MAX], first;
void merge_sort(int l, int r){
if (l >= r){
return;
}
int mid = (l+r) / 2;
merge_sort(l, mid);
merge_sort(mid+1, r);
int x = l, y = mid+1, i = l;
while (x <= mid || y <= r){
if (x <= mid && (y > r || a[x].t >= a[y].t)){
b[i++] = a[x++];
}else {
b[i++] = a[y++];
}
}
for (i = l; i<=r; i++){
a[i] = b[i];
}
}
priority_queue<Node> q;
void init(){
while (!q.empty())q.pop();
}
int solve(int n){
int m, res = 0, ans = MAX;
for (m = 0; m<n-1; m++){
if (a[m].t > first.t){
q.push(a[m]);
res++;
}else{
break;
}
}
ans = min(ans, res);
while (!q.empty()){
Node tmp = q.top();
if (tmp.x <= first.t){
q.pop();
first.t -= tmp.x;
res--;
for (; m<n-1; m++){
if (a[m].t > first.t){
q.push(a[m]);
res++;
}else{
break;
}
}
ans = min(ans, res);
}else{
break;
}
}
ans = min(ans, res);
return ans+1;
}
int main(){
int n;
while (scanf("%d", &n) != EOF){
init();
scanf("%lld%lld", &first.t, &first.w);
for (int i = 0; i<n-1; i++){
scanf("%lld%lld", &a[i].t, &a[i].w);
a[i].x = a[i].w-a[i].t+1;
}
merge_sort(0, n-2);
printf("%d\n", solve(n));
}
return 0;
}