算法设计与编程 栓奶牛 二分模板题

88 阅读2分钟

题意解读

当n=4,k=6,木桩的位置为 0,3,4,7,8,90,3,4,7,8,9时,题目提供了两个方案:

image.png image.png

第1个方案的最近距离是1,第二个方案的最近距离是2,因此我们可以舍弃掉第一个方案。现在我们来看看第二个方案得出的最近距离是不是答案(最近距离的最大值)。什么叫最近距离的最大值呢?

我们观察图不难发现,如果两头牛之间的最近距离大于2,那么就不能保证每头牛都有木桩栓。因此最近距离最大不能超过2,因此2就是答案(奶牛之间最近距离的最大值)。

解题思想

求最小数的最大值,我们可以用二分的第二个模板

image.png

因为我们要求最近距离的最大距离,所以我们可以一开始从第一个木桩到最后一个木桩的一半距离开始枚举,即mid=a[n]-a[1]。然后我们需要判断mid是否是满足最近距离的最大距离。如果说所有的牛按照mid距离栓完之后还有木桩没有被栓,说明mid小了,我们就要扩大mid,即往右边走,即l=mid。否则如果最右边的木桩被栓完之后还有奶牛没有被栓,说明我们的mid大了,需要缩小mid,往左边走,即r=mid-1。最后经过一系列循环之后mid就是满足奶牛之间最近距离的最大距离。

code

#include <bits/stdc++.h>
using namespace std;
int n, k, maxlen, ant;
const int N = 1e6 + 10;
long long p[N];

bool check(int mid) {
	int ans = 0;
	int now = 1, next;  //第一个奶牛肯定栓第一个木桩上
	while (now < k)
	{
		next = now + 1;  //下一个位置等于当前位置+1

		while (next <= k && p[next] - p[now] < mid) //最大距离小于mid时就一直循环
		{
			next++;  //往右移
		}
		if (next == k + 1)  //所有木桩都遍历完了就结束
		{
			break;
		}
		ans++;
		now = next;   //更新一下木桩的位置
	}
	return ans >= n;
}


int main() {
	cin >> n >> k >> p[1];

	//首先需要推出所有木桩的位置



	for (int i = 2; i <= k; i++) {
		p[i] = p[i - 1] + ((p[i - 1] * 2357 + 137) % 10) + 1;
	}

	//sort(p + 1, p + n + 1);
	//二分查找所有木桩之间最近距离的最大值
	int l = 1, r = p[k] - p[1];

	while (l < r) {
		int mid = l + r+1>> 1;
		if (check(mid)) {

			l = mid ;
		}
		else
			r = mid - 1;
	}

	cout << r << endl;
	return 0;
}