convention2
题面
虽然在接机上耽误了挺长时间,Farmer John为吃草爱好牛们举行的大会至今为止都非常顺利。大会吸引了世界各地的奶牛。
然而大会的重头戏看起来却给Farmer John带来了一些新的安排上的困扰。他的农场上的一块非常小的牧草地出产一种据某些识货的奶牛说是世界上最美味的品种的草。因此,所有参会的N头奶牛(1≤N≤105)都想要品尝一下这种草。由于这块牧草地小到仅能容纳一头奶牛,这很有可能会导致排起长龙。
Farmer John知道每头奶牛i计划到达这块特殊的牧草地的时间ai,以及当轮到她时,她计划品尝这种草花费的时间ti。当奶牛i开始吃草时,她会在离开前花费全部ti的时间,此时其他到达的奶牛需要排队等候。如果这块牧草地空出来的时候多头奶牛同时在等候,那么资历最深的奶牛将会是下一头品尝鲜草的奶牛。在这里,恰好在另一头奶牛吃完草离开时到达的奶牛被认为是“在等待的”。类似地,如果当没有奶牛在吃草的时候有多头奶牛同时到达,那么资历最深的奶牛是下一头吃草的奶牛。
请帮助FJ计算所有奶牛中在队伍里等待的时间(ai到这头奶牛开始吃草之间的时间)的最大值。
输入格式
文件名:convention2.in:
输入的第一行包含N。以下N行按资历顺序给出了N头奶牛的信息(资历最深的奶牛排在最前面)。每行包含一头奶牛的ai和ti。所有的ti为不超过104的正整数,所有ai为不超过109的正整数。
输出样例
文件名:convention2.out:
输出所有奶牛中的最长等待时间。
输入样例:
5
25 3
105 30
20 50
10 17
100 10
输出样例:
10
在这个例子中,我们有5头奶牛(按输入中的顺序编号为1…5)。奶牛4最先到达(时间10),在她吃完之前(时间27)奶牛1和奶牛3都到达了。由于奶牛1拥有较深的资历,所以她先吃,从她到达开始共计等待了2个单位时间。她在时间30结束吃草,随后奶牛3开始吃草,从她到达开始共计等待了10单位时间。在一段没有奶牛吃草的时间过后,奶牛5到达,在她正在吃草的时间里奶牛2也到达了,在5个单位时间之后能够吃到草。相比到达时间等待最久的奶牛是奶牛3。
题解
- 到了初中以后再次受到了牛吃草问题的洗礼
- 想到暴力模拟应该很简单,但是时间复杂度不优秀。我们选择数据结构维护。
- 我们发现要求某些符合条件的最优值:即每一头牛[在它吃完草结束前到达]的[资历最深]的奶牛,即符合的条件是吃完草前到达,最优值是资历最深。最优值?这不就是优先队列嘛。因此我们可以用优先队列来维护。
- 具体做法是:
暴力找出第一个吃草的牛:按照到达时间为第一关键字,按照资历为第二关键字的顺序的第一个元素。然后将其放入堆中。
如果堆是空的:新放进去。
如果不为空:顺序查找来到时间小于这个牛吃草结束的牛,进堆;以经验为第一关键字。每一次的堆顶就是即将吃的草。 - 预处理:预处理经验值,第i头可以认为是 n − i + 1 n-i+1 n−i+1
- 时间复杂度:不高于 O ( n l o g n ) O(nlogn) O(nlogn)
- 代码实现如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,ans=0;
struct node {
int tim,exp,eat,lt;
}a[maxn];
inline bool cmp(node a,node b) {
if (a.tim!=b.tim) return a.tim<b.tim;
else return a.exp>b.exp;
}//排序
int main(void)
{
freopen("convention2.in","r",stdin);
freopen("convention2.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d",&a[i].tim);
scanf("%d",&a[i].eat);
a[i].exp=n-i+1;
}
sort(a+1,a+n+1,cmp);
priority_queue < pair< int , int > > q;
q.push(make_pair(a[1].exp,1));//用pair类型存储,经验为第一关键字
int now=1,last_time=a[1].tim,cnt=0;
while (now<=n)//now表示进堆元素
{
while (q.size())//堆为空
{
int p=q.top().second;q.pop();
ans=max(ans,last_time-a[p].tim);//更新等待时间
while (a[now+1].tim<=last_time+a[p].eat && now<n)
{
now++;
q.push(make_pair(a[now].exp,now));
}//将结束时间前的进堆
last_time+=a[p].eat;//last_time存储上一头牛结束吃草的时间
}
now++,last_time=a[now].tim;
q.push(make_pair(a[now].exp,now));//新进堆.如果now到n了也不要紧,下一层反正会退出
}
cout<<ans<<endl;
return 0;
}