洛谷P2678:跳石头(贪心 + 二分)

题目背景

一年一度的“跳石头”比赛又要开始了!

题目描述

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 NN 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 MM 块岩石(不能移走起点和终点的岩石)。

输入格式

第一行包含三个整数 L,N,ML,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L \geq 1L≥1 且 N \geq M \geq 0NM≥0。

接下来 NN 行,每行一个整数,第 ii 行的整数 D_i( 0 < D_i < L)D**i(0<D**i<L), 表示第 ii 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输出格式

一个整数,即最短跳跃距离的最大值。

输入输出样例

输入 #1复制

25 5 2 
2
11
14
17 
21

输出 #1复制

4

说明/提示

输入输出样例 1 说明:将与起点距离为 2和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17 的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。

20分做法:直接暴力即可

50分做法:考虑DP,f[i][j]表示在前i块石头移走j块石头的最短距离,转移即可

60分做法:考虑贪心,每次删除间距最小的,用堆维护

100分做法:考虑二分答案后贪心,先二分这个距离使其变为判断可行性问题,然后从前往后扫,一旦这个石头到上一个选的石头的距离小于这个二分的答案就把这块石头移走

这样显然是正确的,很容易证明先移一定比后移好,所以这个算法是正确的

【代码】

#include<bits/stdc++.h>
using namespace std;
int i ,l, n, m, w, mid, pos, ans, a[50000 + 10];
inline int read() {
	int s = 0, w = 1;
	char ch = getchar();
	while (ch<'0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); }
	while (ch >= '0'&&ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * w;
}
bool ok(int x) {
	for ( w = pos = 0, i = 1; i <= n; ++i)
		if (a[i] - pos < x)
			w++;
		else
			pos = a[i];
	return w <= m;
}
int main() {
	l = read(), n = read(), m = read();
	for (int i = 1; i <= n; ++i)
		a[i] = read();
	a[++n] = l;
	for (int left = 1, right = l; left <= right;)if (ok(mid = left + right >> 1))ans = mid, left = mid + 1; else right = mid - 1;
	cout << ans << endl;
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/RioTian/p/12931778.html