01 / 本课学习路线
本课学习路线
阅读与推演约 110 分钟,练习约 65 分钟,进阶练习另需约 25 分钟
02 / 学习目标与先修自测
学完本课你能做什么,以及开始前需要会什么
二分答案的题只有两个部件:一个 O(n) 的判定函数,和一个不会死循环的二分。写对判定、选对中点方向,题就做完了。
| 学完后能做的事 | 正文位置 | 检查方式 |
|---|---|---|
| 识别「最大值最小化 / 最小值最大化」句式并说出单调性论证 | 第 03 节 | 自查第 3 条 |
| 写二分前先单独测试判定函数 | 第 05 节 | 自查第 4 条、代码自测 |
| 说明两道题的中点选择与区间收缩方向为什么相反 | 第 06 节 | 自查第 2 条、练习 4、5 |
| 端点的取法有依据:下界 max(t)、上界 sum(t) 各是为什么 | 第 04、05 节 | 自查第 5 条、练习 3 |
| 独立通过 AI018、P2497 | 第 08 节 | 必做任务 1、2 |
先修自测:下面 5 题请先自己写答案,再展开对照。答不出的按括号里的位置补看再回来。本课假定你已完成模块 2 的「二分边界与二分答案」和模块 3 的「广度优先搜索」。
| 题号 | 题目 | 补看位置 |
|---|---|---|
| 自测 1 | lo = 5、hi = 6:(lo + hi) // 2 和 (lo + hi + 1) // 2 各是多少? | 二分边界与二分答案第 04 节 |
| 自测 2 | while lo < hi 的循环,结束时 lo 和 hi 是什么关系? | 二分边界与二分答案第 05 节 |
| 自测 3 | max([7, 2, 5, 10, 8]) 与 sum(...) 各是多少? | 常用内置函数 |
| 自测 4 | 在函数里定义另一个函数 check,它能读到外层的列表 t 吗? | 作用域 |
| 自测 5 | 网格上从起点出发、只走满足条件的格子、判断能否到终点——用哪种搜索、队列里放什么? | 广度优先搜索:网格与多源扩散第 03 节 |
展开先修自测答案
自测 1:5 和 6。左中点向下取、右中点向上取;区间只剩两个数时,用错中点会让区间不再缩小——第 06 节。
自测 2:lo == hi,就是答案所在的那一个值。本课两道题都用这个循环形状。
自测 3:10 与 32。它们是 AI018 二分的下界和上界:最大分片和不可能小于最长的单条,也不必大于全部放一片。
自测 4:能。嵌套函数可以直接读取外层变量,本课的判定函数就这样写在主程序里。
自测 5:广度优先搜索(BFS),队列里放坐标;入队时标记已访问。P3799 的判定函数就是一次 BFS。
03 / 概念与术语
最值句式、可行域、判定函数、端点、中点与收缩方向
「最大值最小化」「最小值最大化」两种句式的共同结构:目标越宽松越容易做到——可行的 L 构成一段前缀或后缀,这就是二分的前提。
| 术语 | 含义 | 代码里的位置 |
|---|---|---|
| 最值句式 | 「让最大的尽量小」(AI018)或「让最小的尽量大」(P2497、P3799) | 题面里的那句话 |
| 可行域 | 所有能做到的目标值 L 的集合;单调时是一段前缀(≤ 某值都可行)或后缀(≥ 某值都可行) | 画在纸上 |
| 判定函数 check(L) | 给定 L,用一个 O(n) 的贪心或搜索回答「能不能做到」 | def check(limit) |
| 端点 lo / hi | 可行域一定落在 [lo, hi] 内,且两端有依据 | lo, hi = max(t), sum(t) |
| 求最小可行值 | 可行域是后缀,找左端点:左中点 + 可行则 hi = mid | AI018 |
| 求最大可行值 | 可行域是前缀,找右端点:右中点 + 可行则 lo = mid | P2497、P3799 |
补充学习(选学)为什么「段数少于 k」也算可行约 4 分钟细分不增大最大值的一句话证明,和它失效的场景
把任何一段一分为二,两个新段的和都不超过原来那段——最大值只会不变或变小,所以最少段数 ≤ k 时,总能补切到恰好 k 段(每段非空要求 n ≥ k,题目已保证)。注意这依赖「耗时非负」:如果元素可以为负,细分可能改变最大值,上述推论不再成立——此时必须按题目定义重新设计判定条件。
04 / P2497 木板题
判定:把短木板补到 L 的木料够不够;求最大可行值
P2497「最短木板长度」:第一行木板数 n 与木料长 m,第二行 n 块木板长度;木料可任意切割拼到木板上,让最短木板尽量长,输出最短木板的最大长度。题面示例 1:5 3 / 4 5 3 5 5 → 5;示例 2:5 2 / 4 5 3 5 5 → 4。
| L | 各块需补 | 需要木料 | 与 m = 4 比较 | 可行 |
|---|---|---|---|---|
| 5 | 2 / 0 / 0 | 2 | 2 ≤ 4 | ✓ |
| 6 | 3 / 1 / 0 | 4 | 4 ≤ 4(恰好用完) | ✓ |
| 7 | 4 / 2 / 1 | 7 | 7 > 4 | ✗ |
可行域 {…, 5, 6},是一段前缀,答案取右端点 6——求「最大可行值」。端点:lo = min(a) = 3(不补也可行),hi = min(a) + m = 7(全部木料补最短那块,再高不可能)。
示例 2(5 2 / 4 5 3 5 5)的二分:lo = 3,hi = 5,右中点
mid = (3+5+1)//2 = 4:需补 1(把 3 补到 4)≤ 2 ✓ → lo = 4 mid = (4+5+1)//2 = 5:需补 1+2 = 3 > 2 ✗ → hi = 4 lo == hi == 4 → 输出 4(示例 1 木料 3 时 mid = 5 可行,输出 5)
题目页参考题解是「从最短开始逐级补齐」的模拟写法,与二分答案得到同一结果;本课用二分是为了练「判定 + 收缩」这个通用方法。
05 / AI018 数据分片调度
判定:限额 L 之下贪心分段数出段数;五个 L 的判定表与四轮二分
AI018「数据分片调度」:第一行 n k(1 ≤ k ≤ n ≤ 2000),第二行 n 个耗时(0 ≤ t ≤ 10⁶);按原顺序切成恰好 k 个连续非空分片,最小化最大分片和。题面示例 1:5 2 / 7 2 5 10 8 → 18;示例 2:4 1 / 5 9 1 7 → 22。
| L | 贪心分段 | 段数 | 可行(≤ 2) |
|---|---|---|---|
| 10 | 7+2 | 5 | 10 | 8 | 4 | ✗ |
| 17 | 7+2+5 | 10 | 8 | 3 | ✗ |
| 18 | 7+2+5 | 10+8 | 2 | ✓ |
| 31 | 7+2+5+10 | 8 | 2 | ✓ |
| 32 | 全部一片 | 1 | ✓(段数少于 k 也可行) |
可行域 {18, 19, …},是一段后缀,答案取左端点 18——求「最小可行值」。贪心分段:能放进当前片就放,放不下才开新片,这样段数最少;单条 > L 直接不可行。
| 轮 | lo | hi | mid | check(mid) | 收缩 |
|---|---|---|---|---|---|
| 1 | 10 | 32 | 21 | ✓(2 段) | hi = 21 |
| 2 | 10 | 21 | 15 | ✗(7+2+5 \| 10 \| 8 → 3 段) | lo = 16 |
| 3 | 16 | 21 | 18 | ✓ | hi = 18 |
| 4 | 16 | 18 | 17 | ✗ | lo = 18 |
lo == hi == 18,输出 18。先用第一张表的几个 L 单独测过判定函数,再进入二分——判定错了,二分只会把错误收缩得很快。
AI018 的三个易错点
① 二分下界是 max(t) 而不是 0——单条样本不可再切;② 判定里先检查单条是否超限;③ 段数少于 k 也算可行:耗时非负,把某段再切开不会增大最大值,所以判定条件是「最少段数 ≤ k」,写成「== k」会在 3 3 / 3 1 4 上输出 8(正确 4)。
06 / 中点与收缩方向
求最小可行值与求最大可行值:中点和收缩方向必须成对改
两个循环形状只差两处,但改一半就死循环。
| 目标 | 可行域 | 中点 | 判定为真 | 判定为假 | 例子 |
|---|---|---|---|---|---|
| 最小可行值 | 后缀 {L ≥ 答案} | (lo + hi) // 2 | hi = mid | lo = mid + 1 | AI018 |
| 最大可行值 | 前缀 {L ≤ 答案} | (lo + hi + 1) // 2 | lo = mid | hi = mid - 1 | P2497、P3799 |
只改一半为什么死循环:lo = 5、hi = 6、check(5) 为真
求最大可行值却用左中点:mid = (5+6)//2 = 5,check(5) 真 → lo = 5;区间 [5, 6] 没变,永远循环 求最小可行值却用 lo = mid:mid = 5,check(5) 真 → lo = 5;同样不动 规则:hi = mid 配左中点,lo = mid 配右中点——「可行时保留 mid」的那一侧,中点要往另一侧偏
07 / P3799 路测线路
判定函数是一次广度优先搜索:只走信号 ≥ L 的格子,起点能否到终点
P3799「寻找最优的路测线路」(进阶):第 1 行行数 R、第 2 行列数 C,随后 R 行信号值;从 [0,0] 到 [R−1,C−1] 可上下左右走,路线得分 = 路线上最差的格子,输出最优路线的得分。题面示例:3 / 3 / 5 4 5 / 1 2 6 / 7 4 6 → 4(路线 5→4→5→6→6)。
| L | 允许走的格子 | 起点到终点 | 可行 |
|---|---|---|---|
| 4 | 除 1、2 之外的全部 | 5→4→5→6→6 | ✓ |
| 5 | 5、5、6、7、6 | 起点右边是 4、下边是 1,走不出去 | ✗ |
| 6 | 6、7、6 | 起点 5 < 6 | ✗ |
可行域 {…, 4},答案 4。端点:lo = 全图最小值,hi = min(起点, 终点)——路线必经起点和终点,得分不可能超过它们。题目页参考题解用「每次走信号最大的邻格」的优先队列搜索,与二分 + BFS 结果相同。
为什么不能只允许向右向下:5 行 3 列 9 9 9 / 1 1 9 / 9 9 9 / 9 1 1 / 9 9 9
只走右、下:从 (0,0) 到 (4,2) 必经第 1 行或第 3 行里的 1 → 得分 1 允许四个方向:沿第 0 行向右、第 2 列向下、第 2 行向左、第 0 列向下、第 4 行向右 → 全程 9 → 得分 9 转移方向不确定时不能用「只从上、左来」的动态规划,要用搜索
08 / 从判定到程序
三道题的完整参考程序,每一步落在哪几行
先自己写完并提交一次,再展开对照。
| 步骤 | AI018 | P2497 | P3799 |
|---|---|---|---|
| 句式 | 最大分片和最小 | 最短木板最长 | 最差格子最好 |
| 判定函数 | 贪心分段数段数 ≤ k | 补齐木料 ≤ m | BFS 能否连通 |
| 端点 | max(t)、sum(t) | min(a)、min(a) + m | 全图最小、min(起点, 终点) |
| 中点 / 收缩 | 左中点,真则 hi = mid | 右中点,真则 lo = mid | 同 P2497 |
| 答案 | lo | lo | lo |
AI018 二分代码框架:求最小可行值
Pythonimport sys
def main() -> None:
data = sys.stdin.read().split()
# n, k 与耗时数组 ts
def check(limit: int) -> bool:
# 待完成:贪心判定——按原顺序把元素加入当前分段,加入后超过 limit 就开始新的一段;
# 最后比较「最少段数 <= k」(段数少于 k 时可继续细分非空分段,仍视为可行)
...
lo, hi = max(ts), sum(ts) # 下界是单条最大值,不是 0
while lo < hi:
mid = (lo + hi) // 2 # 求「最小的可行值」:左中点 + hi=mid
if check(mid):
hi = mid
else:
lo = mid + 1
print(lo)
main()判定函数 O(n)、二分 O(log(sum)),总 O(n log S)。木板题求最大可行值时改右中点 (lo+hi+1)//2 且判定为真则 lo=mid——中点与收缩方向要成对改动。
展开完整参考程序 1:AI018 数据分片调度(先自己写完并提交一次,再展开对照)
完整程序:AI018(标准输入 → 标准输出)
Pythonimport sys
data = sys.stdin.read().split()
n, k = int(data[0]), int(data[1])
t = [int(x) for x in data[2:2 + n]]
def check(limit): # 每片耗时之和都不超过 limit 时,最少要切几片?≤ k 即可行
pieces, cur = 1, 0
for x in t:
if x > limit: # 单条就超限:怎么切都不行
return False
if cur + x > limit: # 放不进当前片:开新片
pieces += 1
cur = x
else:
cur += x
return pieces <= k # 片数少于 k 也可行:再切开不会增大最大值
lo, hi = max(t), sum(t) # 下界:最长的单条;上界:全部放一片
while lo < hi: # 求最小可行值:左中点,可行则 hi = mid
mid = (lo + hi) // 2
if check(mid):
hi = mid
else:
lo = mid + 1
print(lo)用两组题面示例(18、22)、练习 2 的 k = 3(14)和 3 3 / 3 1 4(4)核对;n = 2000 时二分 + O(n) 判定在时限内。
展开完整参考程序 2:P2497 最短木板长度
完整程序:P2497(标准输入 → 标准输出)
Pythonimport sys
data = sys.stdin.read().split()
n, m = int(data[0]), int(data[1])
a = [int(x) for x in data[2:2 + n]]
def check(length): # 把所有短于 length 的木板补到 length,木料够不够
need = 0
for x in a:
if x < length:
need += length - x
return need <= m
lo, hi = min(a), min(a) + m # 下界:不补也可行;上界:全部木料补最短那块
while lo < hi: # 求最大可行值:右中点,可行则 lo = mid
mid = (lo + hi + 1) // 2
if check(mid):
lo = mid
else:
hi = mid - 1
print(lo)用两组题面示例 5 / 4 和第 04 节的 [3,5,6]、m = 4 → 6 核对;题目页参考题解是逐级补齐的模拟写法,结果相同。
展开完整参考程序 3:P3799 寻找最优的路测线路(进阶练习)
完整程序:P3799(标准输入 → 标准输出)
Pythonimport sys
from collections import deque
data = sys.stdin.read().split()
R, C = int(data[0]), int(data[1])
grid = [[int(data[2 + i * C + j]) for j in range(C)] for i in range(R)]
def check(level): # 只走信号 ≥ level 的格子,起点能否到终点
if grid[0][0] < level or grid[R - 1][C - 1] < level:
return False
seen = [[False] * C for _ in range(R)]
seen[0][0] = True
q = deque([(0, 0)])
while q:
x, y = q.popleft()
if (x, y) == (R - 1, C - 1):
return True
for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1)):
nx, ny = x + dx, y + dy
if 0 <= nx < R and 0 <= ny < C and not seen[nx][ny] and grid[nx][ny] >= level:
seen[nx][ny] = True
q.append((nx, ny))
return False
lo, hi = min(min(row) for row in grid), min(grid[0][0], grid[R - 1][C - 1]) # 答案不超过起点与终点中较小的那个
while lo < hi: # 求最大可行值:右中点,可行则 lo = mid
mid = (lo + hi + 1) // 2
if check(mid):
lo = mid
else:
hi = mid - 1
print(lo)用题面示例 → 4 和第 07 节的 5×3 网格 → 9 核对。判定用 BFS,一次 O(RC)。
09 / 边界、反例与复杂度
错误做法在具体输入上各输出什么
下面每一行都是一个具体的错误程序,给出输入、错误输出与正确输出;把参考程序改成对应写法就能复现。
| 错误做法 | 输入 | 错误输出 | 正确输出 | 判题结果 |
|---|---|---|---|---|
| AI018 判定写成「恰好 k 段」 | 3 3 / 3 1 4 | 8 | 4 | 答案错误(WA) |
| AI018 判定写成「恰好 k 段」 | 8 4 / 5 5 5 5 5 5 5 5 | 40 | 10 | 答案错误(WA) |
AI018 左中点却写 lo = mid | 题面示例 1 | 不结束(lo = 17、hi = 18 时 mid = 17 不可行 → lo = 17 不动) | 18 | 超时(TLE) |
| P2497 右中点却写成左中点 | 3 4 / 3 5 6 | 不结束(lo = 5、hi = 6 时 mid = 5 可行 → lo = 5 不动) | 6 | 超时(TLE) |
| P2497 上界取 max(a) | 2 100 / 1 2 | 2 | 51 | 答案错误(WA) |
| P3799 判定里 ≥ 写成 > | 题面示例 | 3 | 4 | 答案错误(WA) |
| P3799 只允许向右向下的动态规划 | 第 07 节 5×3 网格 | 1 | 9 | 答案错误(WA) |
两行「不结束」:区间停在两个数上不再缩小,程序一直循环直到被判为超时。第五行:木料 100 分给两块木板(1 补 50、2 补 49),最短木板可以到 51,远超原最长木板 2——上界要取 min(a) + m,不是 max(a)。
| 做法 | 时间 | 本课规模下 |
|---|---|---|
| 二分 + O(n) 判定 | O(n log S) | AI018 n = 2000、S ≤ 2×10⁹:约 2000 × 31 步 |
| 二分 + BFS 判定 | O(RC log V) | P3799 20×20 网格、值域小,瞬间完成 |
| 枚举所有切法 | O(C(n−1, k−1)) | n = 2000 不可行 |
10 / 渐进练习与参考答案
跟做 → 改一个条件 → 独立实现 → 迁移
每题先在纸上或文件里做完,再展开答案。
练习 1(跟做):按第 05 节两张表的格式,对示例 2 4 1 / 5 9 1 7 写出判定表(L 取 9、21、22)和二分过程。
展开练习 1 答案
check(9):9 > 9?否,但 5+9 > 9 开新片……5 | 9 | 1+7 → 3 段 > 1 ✗;check(21):5+9+1 | 7 → 2 段 ✗;check(22):全部一片 ✓。二分 lo = 9、hi = 22:mid 15 ✗ → lo 16;mid 19 ✗ → lo 20;mid 21 ✗ → lo 22;输出 22。
练习 2(改一个条件):示例 1 的 k 从 2 改成 3,答案是多少?哪一种切法达到它?
展开练习 2 答案
14:7+2+5 | 10 | 8。判定和二分都不用改,只是 check 里的 k 变了;下界仍是 10。
练习 3(改一个条件):P2497 的上界为什么不能取 max(a)?用 2 100 / 1 2 说明。
展开练习 3 答案
木料 100 全部补给长度 1 的木板,两块木板可以是 51 和 2?不对——最短的是 2。再把木料分给两块:都补到 51 需要 50 + 49 = 99 ≤ 100,所以答案 51。上界取 max(a) = 2 只会输出 2。上界的依据是「最短木板最多能长到 min(a) + m」。
练习 4(独立实现):把 AI018 写成函数 min_max_piece(t, k),用两组示例、练习 2、k = n、含 100 的下界用例、含 0 的用例各写一条断言。
展开练习 4 答案
min_max_piece 的参考实现(自带断言)
Pythondef min_max_piece(t, k):
def check(limit): # 每片和 ≤ limit 时最少切几片,≤ k 即可行
pieces, cur = 1, 0
for x in t:
if x > limit:
return False
if cur + x > limit:
pieces += 1
cur = x
else:
cur += x
return pieces <= k
lo, hi = max(t), sum(t)
while lo < hi: # 求最小可行值:左中点 + 可行则 hi = mid
mid = (lo + hi) // 2
if check(mid):
hi = mid
else:
lo = mid + 1
return lo
assert min_max_piece([7, 2, 5, 10, 8], 2) == 18 # AI018 题面示例 1(第 05 节表)
assert min_max_piece([7, 2, 5, 10, 8], 3) == 14 # 练习 2:k = 3
assert min_max_piece([5, 9, 1, 7], 1) == 22 # 只切一片 = 总和
assert min_max_piece([3, 1, 4], 3) == 4 # k = n:答案是最大单条
assert min_max_piece([1, 1, 100, 1], 2) == 101 # 下界 max(t) 的意义
assert min_max_piece([0, 0, 7, 0, 3], 2) == 7 # 含 0先单独跑 check(17)、check(18) 再跑二分:断言全过时,判定与收缩两部分都对。
练习 5(迁移):把 P2497 写成函数 max_min_board(a, m),用两组示例、第 04 节的 [3,5,6]、练习 3 的用例各写一条断言。中点和收缩方向与练习 4 有哪两处相反?
展开练习 5 答案
max_min_board 的参考实现(自带断言)
Pythondef max_min_board(a, m):
def check(length): # 把所有短于 length 的木板补到 length,木料够不够
need = 0
for x in a:
if x < length:
need += length - x
return need <= m
lo, hi = min(a), min(a) + m # 上界:全部木料补最短那块
while lo < hi: # 求最大可行值:右中点 + 可行则 lo = mid
mid = (lo + hi + 1) // 2
if check(mid):
lo = mid
else:
hi = mid - 1
return lo
assert max_min_board([4, 5, 3, 5, 5], 3) == 5 # P2497 题面示例 1
assert max_min_board([4, 5, 3, 5, 5], 2) == 4 # 题面示例 2
assert max_min_board([3, 5, 6], 4) == 6 # 第 04 节表
assert max_min_board([1, 2], 100) == 51 # 上界取 max(a) 会得 2两处相反:中点 (lo + hi + 1) // 2,可行时 lo = mid。
11 / 读题要求与复习自评
三道题的要求对照,以及完成本课之后怎么复习
提交前把下表过一遍;题目页的题面与样例是最终依据。
| 项目 | AI018 数据分片调度 | P2497 最短木板长度 | P3799 路测线路 |
|---|---|---|---|
| 输入 | 「n k」;一行耗时 | 「n m」;一行木板长 | R;C;R 行信号 |
| 输出 | 最小的最大分片和 | 最短木板的最大长度 | 最优路线得分 |
| 句式 | 最大值最小化 | 最小值最大化 | 最小值最大化 |
| 判定 | 贪心分段数 ≤ k | 补齐木料 ≤ m | BFS 连通 |
| 端点 / 中点 | max(t)..sum(t);左中点 | min(a)..min(a)+m;右中点 | 全图最小..min(起点,终点);右中点 |
| 示例 | 5 2 / 7 2 5 10 8 → 18 | 5 3 / 4 5 3 5 5 → 5 | 3 / 3 / 三行 → 4 |
需要对照解法时,展开本页第 08 节的三份完整参考程序。复习与自评:本课的「学习完成检查」六条是自评,不改变题目的通过(AC)状态,本课算完成的条件以页面下方「学习完成检查」处的说明为准。复习时用三个问题自测:① 不看正文,写出两种目标各自的中点与收缩方向;② 不看表格,重算示例 1 在 L = 17、18 的段数;③ 说出三道题端点的依据。答不出哪一条,就回到对应的节重读,再做第 10 节对应的练习。
12 / 练习
按顺序完成本课的任务
必做题已通过 0/2 道;进阶练习已通过 0/1 道
写判定函数并用三个 L 单独测试
代码自测自主练习练习重点:AI018 的贪心判定:限额下分段、统计段数、与 k 比较;预计用时:15 分钟
完成标准:三个断言全部通过,能解释 check(17) 为什么是假
需要时查看提示
从左到右分段:加入当前元素后不超过上限就累加,否则开始新的一段。不要忘了开头处理「单条超过上限(limit)直接返回 False」。用下面的断言自测;第 05 节第一张表就是这三个 L 的手算。
自测代码(复制到你的代码文件中运行,检查输出是否一致)
ts = [7, 2, 5, 10, 8]
# check(limit) = 能否切成不超过 k=2 段、每段和 <= limit
assert check(17) == False # 7+2+5 | 10 | 8 → 3 段,超过 k=2 段
assert check(18) == True # 7+2+5 | 10+8 → 2 段
assert check(31) == True # 7+2+5=14 | 10+8=18,两段都 ≤ 31(连续切分只有 7/25、9/23、14/18、24/8 四种切法)
# 三个断言均通过后,再在二分搜索中调用 checkAI018 · 数据分片调度
必做任务 1练习重点:二分答案 + 贪心判定;先写判定再收缩;预计用时:30 分钟
完成标准:能整段说出「句式 → 单调 → 判定 → 端点 → 收缩」五步
需要时查看提示
下界 max(t)、上界 sum(t)。判定条件是最少段数 ≤ k(不是恰好等于)。左中点(mid)、可行则 hi = mid。C++/Java 的段和与 sum 用 64 位。第 05 节有判定表与二分逐轮表。
P2497 · 最短木板长度
必做任务 2练习重点:求「最大可行值」:右中点(mid)+ lo=mid 的写法;预计用时:20 分钟
完成标准:能说出这题和 AI018 在中点与收缩方向上的两处相反
需要时查看提示
判定函数 check(L) = 把所有短于 L 的木板补到 L 所需木料 ≤ m。端点:lo = min(a)(不补也可行),hi = min(a) + m(全部木料补最短的木板)。用右中点 (lo+hi+1)//2,否则 lo=5、hi=6 且 check(5) 为真时会一直循环、无法收敛。第 04 节有判定表。
P3799 · 寻找最优的路测线路
进阶练习 1进阶练习练习重点:「路线最差格子的最大化」:二分阈值 + 只走 ≥ 阈值格子的连通性判定;预计用时:25 分钟
完成标准:能说出判定函数为什么用广度优先搜索(BFS)而不是贪心
需要时查看提示
输入前两行分别是行数、列数。check(L) = 只允许走信号 ≥ L 的格子时,起点能否连通到终点(一次 BFS)。二分域是格子值的范围,上界取 min(起点, 终点),求最大可行 L。这里会用到模块 3 · 第 2 课 的网格 BFS;第 07 节说明了为什么不能只向右向下。
提交结果
提交结果说明与处理方法
- WA
答案错误
四个常见错误:判定条件写成「恰好 k 段」、木板题上界取 max(a)、判定里 ≥ 写成 >、判定内部的贪心分段写错。第 09 节的表给出了每种错误的具体输出
- PE
格式错误
输出一个整数,末尾一个换行
- RE
运行错误
k > n 或空段——题目约束 1 ≤ k ≤ n,读入顺序不要弄反;P3799 行数列数各占一行
- TLE
超时
两种原因:中点与收缩方向只改了一半(区间不再缩小);判定函数里排序或嵌双循环
- AC
通过
口述木板题的中点选择与收缩方向;如仍无法说明,用 lo = 5、hi = 6 的两元素区间再次推演
13 / 学习完成检查
本课学习完成检查
完成本课需要:必做题全部通过,并勾选本课的全部学习完成检查;进阶练习、基础加练与复习题单独统计,不影响完成状态。登录后,勾选记录会保存到账号,并更新课程总览的完成状态。