解题思路
设
f
i
]
fi]
fi]表示f跳到第i个格子的最大得分。
则
f
[
i
]
=
m
a
x
x
j
+
d
−
g
<
=
x
i
<
=
x
j
+
d
+
g
(
f
j
+
s
i
)
f[i]=max_{x_j+d-g<=x_i<=x_j+d+g}(f_j+s_i)
f[i]=maxxj+d−g<=xi<=xj+d+g(fj+si)
用单调队列维护f[i]的值,注意s_i可能是负数,对每个我们不能走的格子一开始要设成负无穷。
考虑优化当
g
=
w
g=w
g=w时,如果
f
[
i
]
>
=
k
f[i]>=k
f[i]>=k有解,则当g
>
w
>w
>w时,
f
[
i
]
>
=
k
f[i]>=k
f[i]>=k也一定有解,所以我们可以用二分来优化枚举g的过程。
》》洛古link
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long;
using namespace std;
int n,d,k;
long long f[500100],maxn,x[500100],s[500100],q[500100];
bool check(int g){
memset(f,0,sizeof(f));
int h=1,t=0,now=0;//now表示当前在哪个格子
int lx=max(1,d-g),rx=d+g;
for(int i=1;i<=n;i++)
{
for(;now<i&&x[now]+lx<=x[i];now++)//枚举可以从哪些格子跳过来,now不用每次赋初值,因为区间在不停往右移
{
while(h<=t&&f[q[t]]<f[now])t--;
q[++t]=now;
}
while(h<=t&&x[q[h]]+rx<x[i])h++;
if(h<=t)
f[i]=f[q[h]]+s[i];
else f[i]=-99999999999;
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("%lld%lld",&x[i],&s[i]);
if(s[i]>0)maxn+=s[i];
}
if(maxn<k)
{
printf("-1");
return 0;
}
int l=0,r=x[n];
while(l<r)
{
int mid=(l+r)/2;
if(check(mid))
r=mid;
else l=mid+1;
}
printf("%d",r);
}