版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
Analysis
当年考NOIP普及组的时候,还不会dp
考场上看到这道题,直接果断弃
时隔两年,我终于能看懂题了/笑
显然是一个二分+dp判断合法
定义
表示到达i这个位置可以获得的最多分数
显然
满足
如果只有后半部分的限制,直接单调队列即可
考虑现在多了前半部分的限制
我们可以维护一个左指针,保证进入单调队列里的值都满足前半部分的限制,后半部分的限制再由队首弹掉
收获:
单调队列每次弹出队列都只能满足一个条件
另一个条件我们用其他方式维护
感觉这个方法很常用【sTO lsr神仙 Orz】
Code
#include<bits/stdc++.h>
#define in read()
#define re register
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return f==1?res:-res;
}
const int N=5e5+10;
typedef long long ll;
int head,tail,q[N];
int n,d,K,x[N];
ll score[N],f[N];
bool check(int g){
head=1;tail=0;f[0]=0;
int up=d+g,down=max(1,d-g);
int l=0;//传说中的指针
for(re int i=1;i<=n;++i){
while(x[i]-x[l]>=down){
while(head<=tail&&f[l]>f[q[tail]]) tail--;
q[++tail]=l;
l++;
}
while(head<=tail&&x[i]-x[q[head]]>up) head++;
if(head<=tail) f[i]=f[q[head]]+score[i];
else f[i]=-1e18;//如果无法到达设为-INF
}
ll ans=-1e18;
for(re int i=0;i<=n;++i) ans=max(ans,f[i]);
return ans>=K;
}
int main(){
n=in;d=in;K=in;
for(re int i=1;i<=n;++i) x[i]=in,score[i]=in;
int l=0,r=1e9,ans=-1;
while(l<=r){
int mid=l+r>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans;
return 0;
}