【ybt高效进阶5-6-5】【luogu P3957】跳房子(二分)(单调队列优化DP)

跳房子

题目链接:ybt高效进阶5-6-5 / luogu P3957

题目大意

有一些点在一条直线上,起点在最左边,然后给出除了起点外其他点根起点的距离和这个点的分数。
然后你要从起点开始,每次都要跳到一个点上,最后你跳过的点的分数和就是你的总分数。
然后初始你只能跳 d 个,你可以花费 x 点费用使得它可以跳的长度范围变成 [max(1,d-x),d+x]。
然后问你要总分数不小于某个值最小要花费多少,如果无论如何都达不到分数就输出 -1。

思路

首先我们发现如果你枚举费用,它就变成了一个单调队列优化 DP。
大概是你先搞出范围,然后每次先看有没有新的可以转移的点,然后再看原来可以转移的点是否不能转移了。

然后你发现它答案满足单调性, 那就直接二分费用,就可以了。

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long

using namespace std;

int n, sta[500001];
ll f[500001], dis[500001], a[500001], d, k;

bool ck(ll mid) {
	ll minn = max(1ll, d - mid), maxn = d + mid;
	memset(f, -0x7f, sizeof(f));
	int l = 1, r = 0, now = 0;
	f[0] = 0;
	for (int i = 1; i <= n; i++) {
		while (dis[now] + minn <= dis[i]) {//新可以转移的点
			while (l <= r && f[sta[r]] < f[now]) r--;
			sta[++r] = now;
			now++;
		}
		while (l <= r && dis[i] - dis[sta[l]] > maxn) l++;//原来的点不可以转移了
		if (l <= r) f[i] = a[i] + f[sta[l]];//要可以转移才转移
		if (f[i] >= k) return 1;//判断是否可以
	}
	return 0;
}

int main() {
	scanf("%d %lld %lld", &n, &d, &k);
	for (int i = 1; i <= n; i++) scanf("%lld %lld", &dis[i], &a[i]);
	
	ll l = 0, r = dis[n], ans = -1;
	while (l <= r) {//二分
		int mid = (l + r) >> 1;
		if (ck(mid)) ans = mid, r = mid - 1;
			else l = mid + 1;
	}
	
	printf("%lld", ans);
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值