csp信奥赛C++高频考点专项训练:【二分答案】案例5:进击的奶牛
题目描述
Farmer John 建造了一个有 N N N( 2 ≤ N ≤ 10 5 2 \leq N \leq 10 ^ 5 2≤N≤105) 个隔间的牛棚,这些隔间分布在一条直线上,坐标是 x 1 , x 2 , ⋯ , x N x _ 1, x _ 2, \cdots, x _ N x1,x2,⋯,xN( 0 ≤ x i ≤ 10 9 0 \leq x _ i \leq 10 ^ 9 0≤xi≤109)。
他的 C C C( 2 ≤ C ≤ N 2 \leq C \leq N 2≤C≤N)头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,Farmer John 想把这些牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好。那么,这个最大的最近距离是多少呢?
输入格式
第 1 1 1 行:两个用空格隔开的数字 N N N 和 C C C。
第 2 ∼ N + 1 2 \sim N+1 2∼N+1 行:每行一个整数,表示每个隔间的坐标。
输出格式
输出只有一行,即相邻两头牛最大的最近距离。
输入输出样例 1
输入 1
5 3
1
2
8
4
9
输出 1
3
AC代码
cpp
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10; // 最大牛栏数量
int n, c, a[N], ma, ans; // n:牛栏总数,c:牛的数量,a[]:牛栏位置数组,ma:最大允许跳过的牛栏数,ans:最终答案
// 检查是否可以将c头牛以最小间隔x放置
bool check(int x) {
int now = a[1]; // 记录已放牛的位置
int cnt = 1; // 已放奶牛数
for (int i = 2; i <= n; i++) { // 遍历后续牛栏
if (a[i] >= now+x) { // 当前牛棚可以放奶牛
cnt++;
now=a[i]; // 更新now的位置
}
}
return cnt>=c; // 返回是否能放得下c头牛
}
int main() {
cin >> n >> c;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + n + 1); // 按位置排序牛栏
// 二分查找最大可行解
int l = 1; // 最小可能间隔
int r = a[n] - a[1]; // 最大可能间隔(首尾距离)
while (l <= r) {
int mid = (l + r) / 2;
if (check(mid)) { // 当前mid可行,尝试更大的值
ans = mid;
l = mid + 1;
} else { // 当前mid不可行,减小最大值
r = mid - 1;
}
}
cout << ans; // 输出答案
return 0;
}
功能分析
-
问题目标
在
n个有序牛栏中放置c头牛,使得相邻牛之间的最小间隔最大化 。这是典型的二分答案问题。 -
核心逻辑
- 排序预处理:将牛栏位置排序,便于计算间隔。
- 二分框架 :在可能的最小间隔范围
[1, 最大首尾距离]内二分搜索。 - 验证函数
check(x):判断是否能以最小间隔x放置c头牛。- now变量:记录已放牛的位置。
- cnt变量:统计以x为最小间隔,最多能放几头牛。
- 判断条件:如果cnt>=c,则放得下;否则放不下。
- 终止条件 :跳过的栏数超过
ma(ma = n - c,即最多允许跳过的栏数)时返回false。
-
复杂度
- 时间复杂度 :排序复杂度为
O(n log n),二分过程为O(log D)(D为最大间隔),每次check为O(n),总复杂度为O(n log n + n log D),适用于n ≤ 1e5。 - 空间复杂度 :
O(n),存储牛栏位置。
- 时间复杂度 :排序复杂度为
-
关键点
- 边界处理:首栏必须放置,保证至少放置一头牛。
完整信奥赛C++普及组CSP-J一等奖通关刷题题单及题解,请关注专栏:
https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
【秘籍汇总】(完整csp信奥赛C++学习资料):
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转
4、csp信奥赛冲刺一等奖有效刷题题解:
信奥赛C++普及组CSP-J一等奖通关刷题题单及题解:
https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
信奥赛C++普及组csp-j初赛&复赛真题题解(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}
