二分 P1824 进击的奶牛
二分 P1824 进击的奶牛
题目描述
Farmer John 建造了一个有 \(N\)(\(2 \leq N \leq 10 ^ 5\)) 个隔间的牛棚,这些隔间分布在一条直线上,坐标是 \(x _ 1, x _ 2, \cdots, x _ N\)(\(0 \leq x _ i \leq 10 ^ 9\))。
他的 \(C\)(\(2 \leq C \leq N\))头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,Farmer John 想把这些牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好。那么,这个最大的最近距离是多少呢?
输入格式
第 \(1\) 行:两个用空格隔开的数字 \(N\) 和 \(C\)。
第 \(2 \sim N+1\) 行:每行一个整数,表示每个隔间的坐标。
输出格式
输出只有一行,即相邻两头牛最大的最近距离。
输入输出样例 #1
输入 #1
5 3
1
2
8
4
9
输出 #1
3
思路
这道题可以类比二分经典题 “跳石头”,具体博客 这里tp 。
牛棚个数为 \(N\) ,要放置的牛的头数为 \(C\) ,且 \(2\le C\le N\),题面保证最近距离一定存在。
同 ”跳石头“,都是求 “最小值的最大”,可以得到最近距离的范围为 \(\left [\ 0, \ a[n] - a[1]\ \right ]\)。
其中 \(a[n] - a[1]\) 为第 \(n\) 个牛棚到第 \(1\) 个牛棚的距离,为最远距离。
然后二分答案。
这里用了一个贪心的思想,就是第 \(1\) 个牛棚一定要有一头牛,这样才能保证 “最大” 这一前提,要不然最远距离小于 \(a[n] - a[1]\) 。
对要检查合法的距离 \(x\) ,遍历所有牛棚。
如果距前一个有牛的牛棚(定位牛棚) \(\ge\) 测试距离 \(x\) ,则更新定位牛棚为 \(a[i]\) ,且 cnt ++
(可以在这放头牛)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, c;
int a[N];
bool check(int x)// 检查最小距离为x时牛棚够不够
{
int cnt = 1;// 第1个牛放在第1个牛棚
int last = a[1];
for (int i = 2; i <= n; i++) {
// 如果两牛棚之间距离大于预设最短距离,可以在第i个牛棚放牛
// 这样可以保证预设距离仍为最近距离
if (a[i] - last >= x) cnt ++, last = a[i];
}
if (cnt >= c) return 1;// 牛棚够
else return 0;
}
int main()
{
cin >> n >> c;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1);
int l = 0, r = a[n] - a[1];
while (l < r) {
int mid = (l + r + 1) >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << l;
}