(题目描述略)
二分答案加动归,设 f i f_i fi 为到达第 i i i 格最大分数,则 f i = m a x ( f j ) + s i f_i = max(f_j) + s_i fi=max(fj)+si, j j j 满足 j < i j < i j<i 且 x i − d − g ≤ x j ≤ x i − d + g x_i - d - g ≤ x_j ≤ x_i - d + g xi−d−g≤xj≤xi−d+g,为维护 m a x ( f j ) max(f_j) max(fj),考虑到随 i i i 增大,可选 f j f_j fj 区间向 j j j 增大方向移动,即每 f j f_j fj 至多进出可选区间一次,双堆维护或单调队列维护均可。其中双堆维护时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),会被卡常(读入优化后可能过);单调队列维护时间复杂度 O ( n ) O(n) O(n)。
需要注意的是,中途某格可能无法到达的情况。在这种情况下,不能直接跳出循环(之后格可能到达),不能赋简单负值(之后可能被加成正值),不能赋极负值(被加负值后越界成正值),需特判不予维护。二分边界值为 m a x ( d − 1 , x n − d ) max(d - 1, x_n - d) max(d−1,xn−d) 需注意。
单调队列版代码如下:
#include<stdio.h>
#define INF (0x7FFFFFFF)
#define MAX_N (500005)
#define MaxInteger(a,b) \
({ \
int __tmp_a=(a),__tmp_b=(b); \
__tmp_a>__tmp_b?__tmp_a:__tmp_b; \
})
int f[MAX_N],fq[MAX_N],s[MAX_N],x[MAX_N];
int main()
{
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
int d,fl,fm,fr,g,gl,gm,gr,k,n;
scanf("%d %d %d",&n,&d,&k);
for(int i=1;i<=n;i++)
scanf("%d %d",&x[i],&s[i]);
x[0]=s[0]=0;
g=gl=-1,gr=MaxInteger(d-1,x[n]-d);
while(gl+1<gr)
{
f[0]=fl=fm=fr=0,fq[0]=fq[1]=2,gm=(gl+gr+1)/2;
for(int i=1;i<=n;i++)
{
while(fr<i&&x[fr]<=x[i]-d+gm)
{
while(fq[0]<fq[1]&&fq[fq[1]-1]<f[fr])
fq[1]--;
fq[fq[1]++]=f[fr++];
}
while(fl<fr&&x[fl]<x[i]-d-gm)
if(fq[fq[0]]==f[fl++])
fq[0]++;
f[i]=fq[0]<fq[1]&&fq[fq[0]]>-INF?fq[fq[0]]+s[i]:-INF;
fm=MaxInteger(fm,f[i]);
}
if(fm<k)
gl=gm;
else
g=gr=gm;
}
printf("%d",g);
return 0;
}
双堆维护版代码如下:
#include<stdio.h>
#define INF (0x7FFFFFFF)
#define MAX_N (500005)
#define MaxInteger(a,b) \
({ \
int __tmp_a=(a),__tmp_b=(b); \
__tmp_a>__tmp_b?__tmp_a:__tmp_b; \
})
#define CmpMax(a,b) ((a)>(b))
#define HeapInsert(hep,key,cmp) \
{ \
int __tmp_i,__tmp_k=(key); \
for(__tmp_i=++hep[0];__tmp_i>1;__tmp_i/=2) \
if(cmp(__tmp_k,hep[__tmp_i/2])) \
hep[__tmp_i]=hep[__tmp_i/2]; \
else \
break; \
hep[__tmp_i]=__tmp_k; \
}
#define HeapDelete(hep,cmp) \
{ \
int __tmp_i,__tmp_j; \
for(__tmp_i=1;__tmp_i*2<hep[0];__tmp_i=__tmp_j) \
{ \
__tmp_j=__tmp_i*2==hep[0]-1||cmp(hep[__tmp_i*2],hep[__tmp_i*2+1])?__tmp_i*2:__tmp_i*2+1; \
if(cmp(hep[__tmp_j],hep[hep[0]])) \
hep[__tmp_i]=hep[__tmp_j]; \
else \
break; \
} \
hep[__tmp_i]=hep[hep[0]--]; \
}
#define HeapTop(hep,hen,cmp) \
({ \
while(hep[0]>0&&hen[0]>0&&hep[1]==hen[1]) \
{ \
HeapDelete(hep,cmp); \
HeapDelete(hen,cmp); \
} \
hep[0]>0?hep[1]:0; \
})
int f[MAX_N],fh0[MAX_N],fh1[MAX_N],s[MAX_N],x[MAX_N];
#define Read \
({ \
char __tmp_c;int __tmp_n=0,__tmp_s=1; \
do __tmp_c=getchar(); \
while((__tmp_c<'0'||__tmp_c>'9')&&__tmp_c!='-'); \
if(__tmp_c=='-')__tmp_s=-1,__tmp_c=getchar(); \
while(__tmp_c>='0'&&__tmp_c<='9') \
__tmp_n=__tmp_n*10+(__tmp_c-'0'), \
__tmp_c=getchar(); \
__tmp_s==1?__tmp_n:-__tmp_n; \
})
int main()
{
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
int d,fl,fm,fr,g,gl,gm,gr,k,n;
scanf("%d %d %d",&n,&d,&k);
for(int i=1;i<=n;i++)
x[i]=Read,s[i]=Read;
x[0]=s[0]=0;
g=gl=-1,gr=MaxInteger(d-1,x[n]-d);
while(gl+1<gr)
{
f[0]=fh0[0]=fh1[0]=fl=fm=fr=0,gm=(gl+gr+1)/2;
for(int i=1;i<=n;i++)
{
while(fr<i&&x[fr]<=x[i]-d+gm)
HeapInsert(fh1,f[fr++],CmpMax);
while(fl<fr&&x[fl]<x[i]-d-gm)
HeapInsert(fh0,f[fl++],CmpMax);
f[i]=HeapTop(fh1,fh0,CmpMax)+s[i];
if(fh1[0]==0||fh1[1]==-INF)
f[i]=-INF;
fm=MaxInteger(fm,f[i]);
}
if(fm<k)
gl=gm;
else
g=gr=gm;
}
printf("%d",g);
return 0;
}