题目传送门:https://www.luogu.org/problemnew/show/P2107
题意:
有一个人(小Z)走在路上,有许多机房在路上,知道它们的坐标,小Z可以走到每一个机房花相应的时间AK,也可以无视着一个机房。从x1走到x2需要花费|x1-x2|的时间,求小Z可以在最多多少个机房AK。
思路(luogu题解上的就是我写的):
1.易知到了某一个点都不能可能再往回走(一定不是最优解,否则在原来就已经进去AK了);
2.因此我们想到了先对坐标排序,如果当前这个点离起点的距离已经大于了规定的疲劳值,就break(不可能走到这个点);
3.我们用一个大根堆来维护从起点走到当前这个点的已走进的机房所消耗的疲劳值(注意不包括路程的疲劳值)如果所有的疲劳值(路程的疲劳值+机房所消耗的疲劳值)已大于规定的疲劳值,分析可知路程的疲劳值不可避免,不可能改变,所以只能少走进一些机房,因为每一个机房都AK一次,所即将疲劳值最大的机房踢掉即可(注意,这是一个while循环的过程)。
代码:
#include<cstdio>
#include<algorithm>
#include<queue>
#define LL long long
using namespace std;
priority_queue<LL> p;
LL n,m,t=0,ans=0,sum=0;
struct node{LL x,y;} a[100001];
bool cmp(node x,node y)
{
return x.x<y.x;
}
int main()
{
LL x,y;
scanf("%lld %lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld %lld",&x,&y);
if(x<=m&&y<=m) a[++t].x=x,a[t].y=y;
}
n=t;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
bool bz=false;
p.push(a[i].y);
sum+=a[i].y+a[i].x-a[i-1].x;
if(sum<=m)
{
bz=true;
ans++;
}
while(sum>m)
{
bz=false;
if(bz) ans--;
sum-=p.top();
p.pop();
}
}
printf("%lld",ans);
}