前言
链接:
https://www.luogu.org/record/show?rid=7915892
这就是之前普及组的第四题…
大意
有n个格子,每个格子有价值。机器人有固定的跳跃距离d,用k个金币改进的话,就可以让跳跃距离在d-k到d+k之间,不过至少要往前跳1个单位长度,每次都必须跳到格子上。要求超过需要的价值求需要消耗的最少金币。
解题思路
二分所需金币数然后
dp,f[i]f[i]表示跳到第i个格子最大价值,然
后
f[i]=f[max:f[l]...f[r];]+c[i]f[i]=f[max:f[l]...f[r];]+c[i]
,这个简单的方程就不解释了,然后单调队列维护
max:f[l]...f[r];max:f[l]...f[r];
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int f[500001],x[500001],c[500001],q[500001];
int n,d,k,l,r,mid;
bool answer()
{memset(f,-1,sizeof(f));//初始化f[0]=0;int head=1,tail=0,j=0;int farst=d+mid,sd=max(1,d-mid);//前后跳跃距离for (int i=1;i<=n;i++){while (x[j]+sd<=x[i])//可以跳到改格{while (head<=tail&&f[j]>=f[q[tail]]) tail--;q[++tail]=j;j++;//加入队列并维护}while (head<=tail&&x[q[head]]+farst<x[i]) head++;//将已经无法跳到的退出if (head<=tail&&f[q[head]]!=-2333333) f[i]=f[q[head]]+c[i];else f[i]=-2333333;//密钥,表示无法到达if (f[i]>=k) return 1;//已经可以退出}return 0;
}
int main()
{scanf("%d%d%d",&n,&d,&k);for (int i=1;i<=n;i++)scanf("%d%d",&x[i],&c[i]);l=1;r=x[n];while (l<=r)//二分{mid=(l+r)/2;if (answer()) r=mid-1;else l=mid+1;}if (l>x[n]) printf("-1");else printf("%d",l);
}