codeforces 725D Contest Balloons

来源:互联网 发布:淘宝客关闭了怎么还扣 编辑:程序博客网 时间:2024/06/05 15:09

题意很容易理解: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;}


0 0
原创粉丝点击