csp信奥赛C++高频考点专项训练:【二分答案】案例5:进击的奶牛

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;
}

功能分析

  1. 问题目标

    n个有序牛栏中放置c头牛,使得相邻牛之间的最小间隔最大化 。这是典型的二分答案问题。

  2. 核心逻辑

    • 排序预处理:将牛栏位置排序,便于计算间隔。
    • 二分框架 :在可能的最小间隔范围[1, 最大首尾距离]内二分搜索。
    • 验证函数check(x) :判断是否能以最小间隔x放置c头牛。
      • now变量:记录已放牛的位置。
      • cnt变量:统计以x为最小间隔,最多能放几头牛。
      • 判断条件:如果cnt>=c,则放得下;否则放不下。
      • 终止条件 :跳过的栏数超过mama = n - c,即最多允许跳过的栏数)时返回false
  3. 复杂度

    • 时间复杂度 :排序复杂度为O(n log n),二分过程为O(log D)D为最大间隔),每次checkO(n),总复杂度为O(n log n + n log D),适用于n ≤ 1e5
    • 空间复杂度O(n),存储牛栏位置。
  4. 关键点

    • 边界处理:首栏必须放置,保证至少放置一头牛。

完整信奥赛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;
}
相关推荐
旖-旎13 小时前
《LeetCode647 回文子串 || LeetCode 5 最长回文子串》
c++·算法·leetcode·动态规划·哈希算法
Darkwanderor14 小时前
对Linux的进程控制的研究
linux·运维·c++
云泽80814 小时前
从零吃透 C++ 异常:抛出捕获、栈展开、异常重抛与编码规范详解
开发语言·c++·代码规范
REDcker14 小时前
libdatachannel 快速入门
c++·webrtc·datachannel
second6016 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++
郝学胜-神的一滴16 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
bksczm16 小时前
linux之线程概念和控制
linux·开发语言·c++
hehelm17 小时前
Linux网络编程—TCP字典翻译系统
linux·开发语言·网络·c++·tcp/ip
hansang_IR17 小时前
【记录】「SCOI2016」三道模拟赛/26.7.12
c++·算法