【Ybtoj 第23章例5】跳房子【单调队列】

在这里插入图片描述
在这里插入图片描述


解题思路

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+dg<=xi<=xj+d+gfj+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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值