first:题目

描述

\(Z\)老师是个菜鸟司机,但买的车却是非常神奇,油箱无限大。 现在他想去\(city\) \(A\)旅游,从出发点到\(city\) \(A\)有\(L\)单位长度,出发时车上有\(P\)单位的油 每走一个单位长度要消耗一单位油。 幸好沿路有一些加油站,每个加油站所能加的油是有限的。 \(Z\)老师太懒了,他希望尽可能少的去加油。 现在问你,他能否顺利到达目的地。 如果能,就输出最少的加油次数,如果不能就输出\(-1\)

输入

第一行有一个整数\(N(N\le10^4)\)。 下面\(N\)行,每行两个整数,分别代表每个加油站与\(city\) \(A\)的距离和本加油站拥有的汽油量。 最后一行有两个整数,\(L(L\le 10^6)\)和\(P(P\le 10^6)\)。

输出

能到达城镇,输出一个整数,代表最少加油的次数。否则输出\(-1\)。

second:分析

乍一眼看这道题,可能会以为每次到油多的加油站加油,但如果前一段的加油站油都很多,但后一段加油站的油很少,每次只选最大油量的加油站可能忽略前一段油较多的加油站使后面一段的加油次数增加甚至无法到达终点。

既然我们无法根据油量的多少来确定,我们可以在每次油不够的时候从已经经过的加油站中选择油最多的加油站加油。

也就是说,如果我们没有油了,我们就加油,因为耗油量跟油的数量没有关系,所以不管什么时候加油都一样,因此我们先不加油,等到没有油的时候再加。

因为题目要求加的油最少,因此我们在油量最大的加油站加油。

third:新知

如果直接枚举车行驶的距离和加油站的油量,时间复杂度是\(O(n^2)\)的,过不了这道题。

因为我们每次只关心油量最多的加油站,所以我们可以用优先队列(堆)来解决。

注意一下,当堆为空时,输出\(-1\),堆为空时代表所以加油站都加了油,没有加油站有油了。

关于堆的具体运用,请看这篇文章,本题时间复杂度为\(O(n\log n)\)

forth:注意

  1. 并不是说到了最后一个加油站就是终点,终点也要当作一个加油站,也就是说有\(n+1\)个加油站。
  2. 注意何时输出\(-1\)。

fifth:代码

#include<bits/stdc++.h>
using namespace std;
priority_queue<int>q;
struct xxx
{
int x,y;
}a[100001];
bool cmp(xxx x,xxx y)
{
return x.x<y.x;
}
int main()
{
int n,l,p,ans=0,w=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].x,&a[i].y);
scanf("%d%d",&l,&p);
n++;
for(int i=1;i<=n;i++)
a[i].x=l-a[i].x;
sort(a+1,a+n+1,cmp);
int sum=p;
for(int i=1;i<=n;i++)
{
int dep=a[i].x-w;
while(sum<dep)
{
if(q.empty())
{
printf("-1");
return 0;
}
int k=q.top();
q.pop();
ans++;
sum=sum+k;
}
q.push(a[i].y);
sum=sum-dep;
w=a[i].x;
}
printf("%d",ans);
return 0;