跳石头

链接

题目给出终点L(最大数),和距起点1~L的各石头(数字),要求我们拿走M个石头(数字),使各石头间的距离最小值最大

例如给出一段序列 0 1 11 22 26 31 37 47(0代表起点,47代表终点),拿走三块石头,使各石头间的距离最小值最大

我们可以拿走 1 26 31,得出的结果为10

这题我们可以采用二分法+贪心的思想

最终结果肯定介于[ 1 , L ] ,我们先假设这个最大值为(1+L)/2,如果偏小,那么结果就介于

[ ( 1 + L ) / 2 , L ],依次不断对区间缩小,直到左区间超过右区间

怎么判定偏大偏小呢,我们不妨思考,如果p成立,那么p-1肯定成立,最大值肯定大于最大值减一

而p+1缺不一定成立(p可能就是最大值)

如果某个石头与上一个石头的距离太小,我们就要移除该石头,直到距离足够

如果,距离已经足够,我们就把索引移到该石头,判定该石头之后的石头与其的距离是否合适

想法有了,代码实现如下

#include<iostream>
#include<vector>
using namespace std;
int main() {
	int L, M, N;
	cin >> L >> N >> M;
	vector<int>stones(N + 2);
	stones[0] = 0;
	stones[N + 1] = L;
	for (int i = 1;i <= N;i++) {
		cin >> stones[i];
	}
	int left = 1, right = L;
	int ans = 0;
	while (left <= right) {
		int maxdis = (left + right) / 2;
		int lastpos = 0;
		int removecount = 0;
		for (int i = 1;i <= N + 1;i++) {
			if (stones[i] - lastpos < maxdis) {
				removecount++;
				if (removecount > M) break;
			}
			else {
				lastpos = stones[i];
			}
		}
		if (removecount <= M) {
			ans = maxdis;//答案暂时定为maxdis,接着判定超过maxdis的是否成立
			left = maxdis + 1;
		}
		else {
			right = maxdis - 1;
		}
	}
	cout << ans;
}

时间复杂度:O(N log L)

空间复杂度:O(N)

全部评论

相关推荐

牛客51274894...:照片认真的吗,找个专门拍证件照的几十块钱整端正点吧,要不就别加照片
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务