备战蓝桥杯国赛【Day 5】

例题 1:浮点二分------计算 √2

项目 内容
来源 蓝桥云课基础模板
类型 浮点二分
核心 精度控制、区间收缩

题目描述

计算 √2,保留 3 位小数。利用 x > 0 时的单调递增性。

输入输出

无输入,输出 1.414

题解

浮点二分与整数二分的区别:

  • 终止条件right - left >= eps(区间长度)
  • eps 选取 :保留 n 位小数,eps = 1e-(n+1)
  • 不判相等:浮点数不存在精确相等
python 复制代码
left, right = 1.0, 2.0
eps = 1e-4  # 保留3位小数,精度取1e-4

while right - left >= eps:
    mid = (left + right) / 2.0
    if mid * mid > 2:
        right = mid  # 中点太大,答案在左半区间
    else:
        left = mid   # 中点太小或正好,答案在右半区间

print(f"{left:.3f}")

推演过程

轮次 区间 mid mid² 判断
1 [1.0000, 2.0000] 1.5000 2.2500 > 2 right = 1.5000
2 [1.0000, 1.5000] 1.2500 1.5625 < 2 left = 1.2500
3 [1.2500, 1.5000] 1.3750 1.8906 < 2 left = 1.3750
4 [1.3750, 1.5000] 1.4375 2.0664 > 2 right = 1.4375
5 [1.3750, 1.4375] 1.4062 1.9775 < 2 left = 1.4062
6 [1.4062, 1.4375] 1.4219 2.0217 > 2 right = 1.4219
7 [1.4062, 1.4219] 1.4141 1.9996 < 2 left = 1.4141

区间长度 1.4219 - 1.4141 = 0.0078 < 0.0001?不对,继续到长度 < eps

最终 left ≈ 1.4142,输出 1.414

关键细节

坑点 说明
eps 太小 循环次数爆炸,1e-6足够,不要1e-10
mid*mid == 2 浮点不能用 ==,永远走 ><= 分支
固定循环次数 for _ in range(100) 也可,更稳定

例题 2:二分答案------巧克力切割(蓝桥杯 P99)

项目 内容
链接 https://www.lanqiao.cn/problems/99/learning/
类型 二分答案(最大值)
时间限制 1s
空间限制 256MB

题目描述

N 块巧克力,H_i × W_i 的长方形。切出 K 块大小相同的正方形,求最大边长。

输入格式

复制代码
N K
H1 W1
H2 W2
...
HN WN

输出格式

一个整数,最大边长。

样例

输入

复制代码
2 5
6 5
5 5

输出

复制代码
2

题解

单调性分析 :边长 x 越大,每块巧克力切出的块数越少,总块数越少。具有单调性。

check(x) :边长为 x 时,能否切出至少 K 块?

  • i 块:(H_i // x) × (W_i // x)
  • 总和 >= K 则合法

二分策略 :求最大值 → check(mid) 合法时,left = mid + 1 尝试更大

python 复制代码
n,k = map(int,input().split())
a = []
for _ in range(n):
    h,w = map(int,input().split())
    a.append((h,w))

# 假定切出的巧克力边长x,能否切出k快
def check(x):
    cnt = 0
    for h,w in a:
        cnt += (h//x)*(w//x)
    return cnt>=k

# 搜索区间
l,r = 1,100000
ans = 1
while l<=r:
    mid = (l+r)//2
    if check(mid):
        ans = mid
        # 求最大
        l = mid+1
    else:
        r = mid-1
print(ans)

推演验证

复制代码
巧克力:[6x5, 5x5],K=5

check(3): (6//3)*(5//3)=2*1=2, (5//3)*(5//3)=1*1=1, 总计3 < 5 → False
check(2): (6//2)*(5//2)=3*2=6, (5//2)*(5//2)=2*2=4, 总计10 >= 5 → True
check(3) False, check(2) True,尝试 check(2) 和 check(3) 之间无整数
答案 = 2 ✓

复杂度分析

指标 复杂度 说明
时间 O(N × log(max(H,W))) 二分约17次,每次遍历N块
空间 O(N) 存储巧克力尺寸

同类对比

题目 区别
例题3(跳石头) 求"最小值最大化",check用贪心
LeetCode 875 求最小速度,check用累加时间

例题 3:二分答案------跳石头(蓝桥杯 P364)

项目 内容
链接 https://www.lanqiao.cn/problems/364/learning/
类型 二分答案(最小值最大化)
标签 贪心 + 二分

题目描述

河道长 L,起点到终点间有 N 块石头。至多移走 M 块,使得最短跳跃距离尽可能大。求这个最大值。

输入格式

复制代码
L N M
D1
D2
...
DN

D_i:第 i 块石头与起点的距离。

输出格式

一个整数,最短跳跃距离的最大值。

样例

输入

复制代码
25 5 2
2
11
14
17
21

输出

复制代码
4

题解

题型识别:"最小值最大化" → 二分答案经典标志。

单调性 :如果最短跳跃距离 x 可行(移走不超过M块),则所有 <= x 的距离也可行?不对,应该是:如果 x 可行,则 x-1 一定可行 (更容易满足)。所以可行解具有单调性,二分找最大的可行 x

check(x) :假设最短距离为 x,贪心判断需要移走多少块:

  • 维护 now_idx:当前所在位置
  • 遍历石头,如果 石头距离 - now_idx < x,移走这块石头
  • 否则跳到这里,更新 now_idx
  • 最后检查终点距离
python 复制代码
import os
import sys

# 请在此输入您的代码
l,n,m = map(int,input().split())
d = []
for _ in range(n):
    d.append(int(input()))

# 最短跳跃距离x,移除岩石数量不超过m,则合法
def check(x):
    # 移除岩石数量
    cnt = 0
    # 上一个位置到起点距离
    last = 0
    for i in range(n):
        # 能跳
        if d[i]-last>=x:
            last=d[i]
        # 太小,搬石头
        else:
            cnt+=1
    # 最后一步特判
    if (l-last)<x:
        # 搬走这块石头,不能直接False
        # return False
        cnt+=1
    return cnt<=m

left,right = 1,l
ans = -1
while left<=right:
    mid = (left+right)//2
    if check(mid):
        ans = mid
        left=mid+1
    else:
        right=mid-1
print(ans)

推演验证

复制代码
L=25, stones=[2,11,14,17,21], M=2

check(4):
  now=0, cnt=0
  i=0: 2-0=2 < 4 → cnt=1, 移走
  i=1: 11-0=11 >= 4 → now=11
  i=2: 14-11=3 < 4 → cnt=2, 移走
  i=3: 17-11=6 >= 4 → now=17
  i=4: 21-17=4 >= 4 → now=21
  终点: 25-21=4 >= 4 ✓
  cnt=2 <= M=2 → True

check(5):
  now=0, cnt=0
  i=0: 2 < 5 → cnt=1
  i=1: 11-0=11 >= 5 → now=11
  i=2: 14-11=3 < 5 → cnt=2
  i=3: 17-11=6 >= 5 → now=17
  i=4: 21-17=4 < 5 → cnt=3 > M=2 → 但继续
  终点: 25-17=8 >= 5
  cnt=3 > M=2 → False

答案在4和5之间,最大可行=4 ✓

关键易错点

错误 正确 后果
忘记终点检查 循环后判断 L - now_idx < x 最后一段距离可能不足
cnt < M 写错 移走最后一块需要 cnt < M 边界WA
贪心方向反了 从左到右,能不移就不移 不是最优解

例题 4:二分答案------第K大元素(蓝桥杯 P3404)

项目 内容
链接 https://www.lanqiao.cn/problems/3404/learning/
类型 二分答案(第K小)
标签 数学 + 二分

题目描述

n × m 乘法表,第 i 行第 j 列为 i × j。求第 k 大的元素。

输入格式

复制代码
n m k

输出格式

一个整数。

样例

输入

复制代码
2 4 4

输出

复制代码
3

题解

题型识别 :"第K小/大" → 二分答案,统计 <= x 的个数。

check(x) :统计乘法表中有多少个元素 <= x

  • i 行:i × j <= xj <= x // i
  • 贡献:min(m, x // i)

二分策略 :找最小的 x,使得 count(<= x) >= k

python 复制代码
import os
import sys

# 请在此输入您的代码
n,m,k = map(int,input().split())

# <=x的数字有多少个
def check(x):
    cnt = 0
    for i in range(1,n+1):
        # i*j<=x -> j<=x//i
        cnt += min(m,x//i)
    return cnt
left,right = 1,n*m
ans = 0
while left<=right:
    mid = (left+right)//2
    # 第k小的数字mid,在原数组中小于等于mid的数字至少有k个
    if check(mid) >= k:
        ans = mid
        right = mid-1
    else:
        left = mid+1
print(ans)

推演验证

复制代码
n=2, m=4, k=4

乘法表:
1  2  3  4
2  4  6  8

排序:[1, 2, 2, 3, 4, 4, 6, 8],第4大=3

check(3):
  i=1: min(4, 3//1=3) = 3
  i=2: min(4, 3//2=1) = 1
  cnt = 4 >= 4 → 合法,尝试更小

check(2):
  i=1: min(4, 2) = 2
  i=2: min(4, 1) = 1
  cnt = 3 < 4 → 不合法

答案 = 3 ✓

复杂度分析

指标 复杂度 说明
时间 O(n × log(n×m)) n,m <= 5×10^5,约38次二分
空间 O(1) 不存矩阵,直接算

关键优化

优化 效果
i > xx//i = 0 提前break,减少循环次数
min(m, x//i) 防止 j 超过列数 m

例题 5:二分查找------基础模板(LeetCode 704)

项目 内容
链接 https://leetcode.cn/problems/binary-search/
类型 二分查找
难度 🟢 简单

题目描述

给定有序数组 nums 和目标值 target,返回索引,不存在返回 -1

题解

最基础的二分,三种写法对比:

写法1:闭区间 [left, right]

python 复制代码
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1
        
        while left <= right:  # 闭区间,left==right有意义
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1  # mid不是答案,从mid+1开始
            else:
                right = mid - 1  # mid不是答案,到mid-1结束
        
        return -1

写法2:左闭右开 [left, right)

python 复制代码
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums)  # right是开边界
        
        while left < right:  # left==right时区间为空
            mid = (left + right) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid  # mid可能是答案,但不能包含mid
        
        return -1

三种写法对比

写法 初始化 循环条件 left更新 right更新 适用场景
闭区间 0, n-1 left <= right mid + 1 mid - 1 找特定元素
左闭右开 0, n left < right mid + 1 mid 找下界/插入位置
开区间 -1, n left + 1 < right mid mid 浮点二分

📊 今日刷题总结

题号 考点 二分类型 难度 核心技巧
1 √2计算 浮点二分 ⭐⭐ eps精度控制
2 巧克力切割 二分答案(最大值) ⭐⭐⭐ check统计块数
3 跳石头 二分答案(最小值最大化) ⭐⭐⭐⭐ 贪心+终点检查
4 第K大元素 二分答案(第K小) ⭐⭐⭐⭐ 数学统计替代遍历
5 二分查找 基础模板 ⭐⭐ 三种区间写法

二分答案万能模板(背下来)

python 复制代码
def binary_search():
    left, right = 最小值, 最大值
    ans = 初始值
    
    while left <= right:
        mid = (left + right) // 2
        if check(mid):   # mid满足条件
            ans = mid    # 记录答案
            left = mid + 1   # 求最大:往右缩
            # right = mid - 1  # 求最小:往左缩
        else:
            right = mid - 1  # 求最大:往左缩
            # left = mid + 1   # 求最小:往右缩
    
    return ans
相关推荐
iuvtsrt2 小时前
C#怎么获取当前所在的函数名_C#如何使用MethodBase读取【代码】
jvm·数据库·python
l1t2 小时前
DeepSeek辅助编写埃拉托斯特尼筛法和Atkin筛法求质数程序比较
开发语言·人工智能·python
Hesionberger3 小时前
LeetCode79:单词搜索DFS回溯详解
java·开发语言·c++·python·算法·leetcode·c#
kkkAloha3 小时前
Python
python
Kiling_07043 小时前
Java方法引用与排序算法精讲
开发语言·python
Mr.朱鹏3 小时前
5.LangChain零基础速通-LCEL链式调用
python·langchain·django·大模型·llm·virtualenv
MZ_ZXD0013 小时前
springboot音乐播放器系统-计算机毕业设计源码76317
java·c语言·c++·spring boot·python·flask·php
qq_283720053 小时前
LangChain 文档切割全攻略:8 大主流切割技术选型 + 实战代码详解
python·langchain·选型·切割
DanCheng-studio4 小时前
网安毕业设计最新项目选题指导
python·毕业设计·毕设