外观
第6周:第三次上机课(完整版)
本页讲评 py3 作业全部 9 题,并提示 py4 作业的 5 题。统计取自 2026-10-14 的 OJ 快照:1553 次提交,其中 847 次 AC、706 次未通过。每次重试分别计数,次数不等于人数。
错误片段根据实际提交匿名改写,只保留需要讲解的部分;所列反例用于解释代码行为,不代表 OJ 的隐藏测试。完整 py3 参考解析已公开;py4 完整答案于 10 月 27 日 13:00 开放(北京时间)。
一、py3 作业讲评
01 · 奇偶数判断
先让条件有明确含义,再确认两条分支都输出。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 取余、赋值与比较、if/else 和缩进 | 第2章第14–17页;第3章第5–8页 | 先让条件有明确含义,再确认两条分支都输出。 |
提交中出现的错误与定位
错误写法 1:用整除判断奇偶
python
if n // 2 != 0:
print("odd")定位与修改: // 得到商,% 得到余数。4 // 2 是 2,错误代码会把偶数 4 判成奇数;判断能否被 2 整除要观察余数是否为 0。
错误写法 2:把比较写成赋值
python
if n % 2 = 0:
print("even")定位与修改: 条件里比较是否相等使用 ==;保存一个值使用 =。if、else 末尾要有冒号,下面的语句需要缩进。
错误写法 3:一个分支没有真正输出
python
else:
("odd")定位与修改: 单独写字符串表达式不会在 OJ 脚本里输出。这个分支也需要 print(...)。用 1、2 分别走两个分支检查。
课堂推演与自测
| n | n % 2 | 应输出 |
|---|---|---|
| 1 | 1 | odd |
| 2 | 0 | even |
| 4 | 0 | even |
已通过提交中的方法对照
通过提交中有完整 if/else 和条件表达式两种写法。课堂先用 if/else,确保每个分支都能执行到输出;条件表达式只是缩短写法,不改变判断条件。
局部写法对照:
python
# 条件表达式,n 已经读入并转成整数
label = "odd" if n % 2 != 0 else "even"先用双分支理解含义,再把“选择一个结果”的简单情形压缩成一行。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
02 · 简单计算器
这是未通过提交最多的一题:154 次未通过,其中 WA 91、RE 39、CE 24。先解决读入类型和异常分支,再讨论除法。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 混合类型输入、逻辑 or、嵌套分支、整数除法 | 第2章第15–17、35、46–47页;第3章第9–10页 | 先解决读入类型和异常分支,再讨论除法。 |
提交中出现的错误与定位
错误写法 1:分割后又调用 input 进行转换
python
a, b, op = input().split()
a = int(input())
b = int(input())定位与修改: 一行已经读完,a、b 是这行拆出的字符串。应写 a = int(a)、b = int(b);再次 input() 会读取不存在的下一行。input(a) 也是再次读入,并且先把 a 当提示输出。
错误写法 2:字符串零与整数零比较
python
a, b, op = input().split()
if b == 0:
print("Divided by zero!")定位与修改: 此时 b 是字符串,"0" == 0 为假。先转换数字,再判断;若随后对零作除法,便会产生除零异常。
错误写法 3:把 or 当成多个相等关系的缩写
python
if op == "+" or "-" or "*" or "/":
pass定位与修改: 该条件包含非空字符串,总会成立。写 op in ["+", "-", "*", "/"],或为每个 or 分别写比较。用 1 2 ? 检查非法运算符是否真的被识别。
错误写法 4:除法返回小数,或把所有零都当作除零
python
if b == 0:
print("Divided by zero!")
# 除法分支中又直接 print(a / b)定位与修改: 3 0 + 是合法加法,应输出 3;除零判断只适用于除法。7 2 / 需要整数商 3,直接 / 会得到 3.5。负数时还需区分向零截断与 // 的向下取整。
错误写法 5:错误提示里的英文标点、单词不一致
python
print("Invalid operator!")定位与修改: 这里是中文全角感叹号;题目要求 Invalid operator!。同样要区分 Divided、Divide 和 Division,不要凭记忆改写固定文本。
课堂推演与自测
| 自测输入 | 应输出 | 检查什么 |
|---|---|---|
7 2 / | 3 | 商要输出整数 |
-7 2 / | -3 | 按本页参考解法向零截断 |
3 0 + | 3 | 非除法允许第二个数为 0 |
3 0 / | Divided by zero! | 在计算前处理除零 |
3 0 ? | Invalid operator! | 非法运算符优先识别 |
-7 // 2 是 -4,int(-7 / 2) 是 -3。参考解法用绝对值整除再恢复符号,避免先转浮点数;这是题意和运算规则的边界讲解,不能据此断言 OJ 隐藏测试包含负数。
已通过提交中的方法对照
通过提交中可见显式 if/elif 分支、先排除非法运算符再计算、以及 eval 计算表达式。课堂使用显式分支,便于定位错误;已 AC 的 // 写法仍需提醒负数舍入方向,不能仅凭 AC 推断测试覆盖。
除法的局部对照(b 已确认非零):
python
quotient = abs(a) // abs(b)
if (a < 0) != (b < 0):
quotient = -quotient这里先求非负的商,再按异号恢复负号。它不需要先通过浮点数计算。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
03 · 计算邮资
82 次未通过。先分清基本费、超重费、加急费,再把费用相加,避免一段嵌套代码同时处理所有情况。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 超重边界、向上取整、独立条件与累加 | 第2章第14–15页;第3章第6、10页 | 先分清基本费、超重费、加急费,再把费用相加,避免一段嵌套代码同时处理所有情况。 |
提交中出现的错误与定位
错误写法 1:整除后无条件加一
python
blocks = (weight - 1000) // 500 + 1定位与修改: 1500 克只超出 500 克,恰好一档;这段算成两档。仅有余数时才加一,或用 math.ceil(extra / 500)。
错误写法 2:用 elif 让超重与加急互斥
python
if weight > 1000:
fee += extra_fee
elif urgent == "y":
fee += 5定位与修改: 1200 克加急时两个条件都应收费。第二个判断应使用独立的 if,不能让“已经超重”阻止加急检查。
错误写法 3:算出了超重费却没有加到总额
python
fee = 8
if weight > 1000:
extra_fee = blocks * 4
print(fee)定位与修改: 定义了 extra_fee 不会自动改变 fee。需要显式累加;同样不能在超重分支中丢掉原来的 8 元基本费。
错误写法 4:括号位置错误
python
blocks = extra + 499 // 500定位与修改: 整除优先于加法,499 // 500 为 0,因此结果等于 extra。整数公式需要 (extra + 499) // 500,先看清谁整体参与除法。
课堂推演与自测
| 重量 | 超出部分 | 档数 | 不加急 | 加急 |
|---|---|---|---|---|
| 1000 | 0 | 0 | 8 | 13 |
| 1001 | 1 | 1 | 12 | 17 |
| 1500 | 500 | 1 | 12 | 17 |
| 1501 | 501 | 2 | 16 | 21 |
可以先用 math.ceil() 理解“不足一档也按一档”,再对照整数公式。三种算法的展开说明见作业 3 提示。
已通过提交中的方法对照
通过提交中可见 math.ceil()、整数公式、整除加余数判断三种实现。三者收费规则一致;选择自己能解释清楚的写法,别把公式里的 500、499 与其他变量混用。
相同超重档数的两种局部写法:
python
# extra 是大于 0 的整数克数
blocks = math.ceil(extra / 500) # 需先 import math
blocks = (extra + 499) // 500两行是两种备选方案,实际代码选一种。用 extra=500 和 501 检查边界。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
04 · 奥运奖牌计数
32 次未通过。读入一次、循环 n 次不是同一回事;每天的数据与累计总数也不是同一个变量。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 循环读入、累加变量、缩进与变量命名 | 第2章第35、46–48页;第3章第14–16页 | 读入一次、循环 n 次不是同一回事;每天的数据与累计总数也不是同一个变量。 |
提交中出现的错误与定位
错误写法 1:输入写在循环外,反复累加第一天
python
daily = input().split()
for day in range(n):
gold += int(daily[0])定位与修改: 应在循环内部读当前这一天的数据。用两天金牌数 1、4 检查:正确总数是 5,不是把第一天的 1 加两次得到 2。
错误写法 2:把 += 写成 =+
python
gold =+ g定位与修改: 这是把正的 g 赋给 gold,每次覆盖;累加应是 gold += g。可以把它展开成 gold = gold + g 理解。
错误写法 3:每日变量覆盖累计变量
python
bronze = 0
for day in range(n):
gold_today, bronze, bronze_today = map(int, input().split())
bronze += bronze_today定位与修改: 示例归纳了原提交中同一个 b 同时代表累计铜牌与当天银牌的问题。输入时就覆盖了累计结果,应让当天值和总数使用不同变量名。
错误写法 4:最终输出了当天数据,或漏掉总奖牌数
python
print(g, s, b, g + s + b)定位与修改: g、s、b 若是循环中当天的数据,最后只代表最后一天。输出的是三种累计总数及它们的总和,共四项。
课堂推演与自测
| 读入天数 | 当天金、银、铜 | 累计金、银、铜 | 总数 |
|---|---|---|---|
| 第 1 天 | 1 2 3 | 1 2 3 | 6 |
| 第 2 天 | 4 5 6 | 5 7 9 | 21 |
两天输入后的唯一一行输出是 5 7 9 21。初始化在循环外,读入与累加在循环内,最终输出再退回循环外。
已通过提交中的方法对照
通过提交中主要是分别维护金、银、铜三个累计值,也有用列表按位置保存各项的写法。课堂采用有含义的变量名,更容易发现 silver/sliver 等拼写错误。
方法一:逐日累加。方法二:分别存入列表后求和。
python
# 逐日累加时,本轮更新
gold_total += gold_today
# 若已把每天金牌存入列表,则在全部读完后
gold_total = sum(gold_each_day)列表方案属于后续组合数据类型内容;当前用累计变量即可,不必为了求和保存所有天的数据。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
05 · 最长单词2
63 次未通过。应先清理句末句点,再比较完整单词长度,最后输出记录的最长单词。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 切片、去句点、按长度比较、并列时保留先出现者 | 第2章第27、29、34–35页;第3章第15–16、22页 | 应先清理句末句点,再比较完整单词长度,最后输出记录的最长单词。 |
提交中出现的错误与定位
错误写法 1:选完最长词才去句点
python
words = sentence.split()
# 先按含句点的长度比较,最后才删除句点定位与修改: cat dog. 中两个单词都是 3 个字母,应选 cat;若先比较,会认为 dog. 有 4 个字符,事后删句点也无法修复选错的单词。
错误写法 2:相等时也更新答案
python
if len(word) >= len(longest):
longest = word定位与修改: 题目要求并列最长时保留第一个。仅在严格更长时更新,即使用 >。用 cat dog. 检查并列情况。
错误写法 3:对单词列表切片,误删最后整个单词
python
words = input().split()
words = words[:-1]定位与修改: 对字符串 [:-1] 去掉最后一个字符;对列表 [:-1] 去掉最后一个元素。I study. 会把 study 整个丢掉。先在原句上处理末尾句点,再分词。
错误写法 4:记录了最长词,却输出循环变量
python
longest = words[0]
# 循环中更新 longest
print(word)定位与修改: 循环结束后 word 是最后遍历的单词,不一定是最长单词。最终应输出保存最优结果的变量。
课堂推演与自测
| 输入 | 应输出 | 检查点 |
|---|---|---|
cat dog. | cat | 去句点后同长,保留第一个 |
I study. | study | 不能丢掉最后整个单词 |
elephant a. | elephant | 最长词不在末尾 |
Hello. | Hello | 只有一个单词也有答案 |
若使用 endswith(),注意拼写中有 s;实际错误提交中多次出现 endwith()。
已通过提交中的方法对照
通过提交中既有逐个扫描并保存最长词,也有 max(words, key=len)。后者的 key 表示比较长度,而非字典序;两种方法都要先处理句点。
局部对照:指定比较依据。
python
# words 已分词并处理末尾句点
longest = max(words, key=len)省略 key 时比较的是字典序。max(["zoo", "elephant"]) 是 zoo;指定 key=len 才按长度选择 elephant。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
06 · 计算直角三角形面积
139 次未通过,其中 PE 49 次。讲评要同时检查控制流程、边的角色和输出字符串,不能只修算式。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 终止条件、break、三角形判定、排序和固定格式输出 | 第2章第16–18、36–40页;第3章第9–10、17、19页;第4章第17页 | 讲评要同时检查控制流程、边的角色和输出字符串,不能只修算式。 |
提交中出现的错误与定位
错误写法 1:输出结束提示,却没有结束循环
python
if a == b == c == 0:
print("program finished")定位与修改: 后面还会继续判三角形,下一轮还会继续读取。应在这里 break,终止判断放在其他几何判断之前。
错误写法 2:固定把两个输入数相乘求面积
python
if longest_side == b:
area = b * c / 2定位与修改: 如果 b 是斜边,直角边应为 a、c。可以先排序成 x <= y <= z,再用 x、y;3 5 4 的面积应为 6.0。
错误写法 3:漏掉逗号后的空格
python
print("not triangle,please input again")定位与修改: 题面要求 not triangle, please input again,逗号后有一个空格。非直角提示和面积后的提示也有同样要求。
错误写法 4:只输出面积,漏掉后缀
python
print(f"{area:.1f}")定位与修改: 面积后还需要 , please input again;最后全零时单独输出 program finished。不能只盯住数值是否为 6.0。
课堂推演与自测
按“全零结束 → 能否成三角形 → 是否直角 → 面积”排序。排序后三角形条件是 x + y > z,等号不成立;平方比较用 ** 2 或自乘,不能用 ^ 2。
text
1 2 3
3 5 4
0 0 0对应输出:
text
not triangle, please input again
6.0, please input again
program finished已通过提交中的方法对照
通过提交中有先排序再判断的写法,也有分别讨论三条边为斜边的写法。排序可以减少重复分支;如果分别讨论,面积必须与当前斜边分支对应。
减少分支的局部写法:
python
x, y, z = sorted([a, b, c])排序后 x、y 是较短两边,z 是最长边。仍需先判断是否构成三角形,再判断勾股关系。
AC 也要用反例检查: 实际有已通过提交在“b 是最长边”的分支仍写 b*c/2。对 3 5 4 会算成 10.0,而正确面积是 6.0;讲义采用修正后的分析,不把 AC 等同于完整的正确性证明。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
07 · 正常血压
47 次未通过。这个题要保存两个不同的信息:这一段有多长,以及历史上最长的一段有多长。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 包含端点的范围判断、当前连续长度与历史最长长度 | 第2章第16–17页;第3章第14–17、22页 | 这个题要保存两个不同的信息:这一段有多长,以及历史上最长的一段有多长。 |
提交中出现的错误与定位
错误写法 1:把正常次数之和当作最长连续时间
python
if normal:
hours += 1
else:
hours += 0定位与修改: “正常、正常、异常、正常”总共正常 3 次,但最长连续时间只有 2。遇异常必须打断当前这一段。
错误写法 2:只保留最后一段
python
if normal:
current += 1
else:
current = 0
# 循环结束只 print(current)定位与修改: 最后一段不一定最长。用“正常、正常、异常、正常”测试,末段为 1,历史最长为 2;需要单独维护 best。
错误写法 3:else 与错误的 if 对齐
python
if normal:
current += 1
if current > best:
best = current
else:
current = 0定位与修改: 这里的 else 表示“没有超过历史最长”,不是“血压异常”。短的新段即使正常也会被清零。重置分支应与判断正常的 if 对齐。
错误写法 4:把端点排除,或把读取放在循环外
python
normal = 90 < systolic < 140 and 60 <= diastolic <= 90定位与修改: 题意包含端点,收缩压两侧也应是 <=。每小时都需重新读取两个数,不能对第一小时反复判断。
课堂推演与自测
| 本小时 | 当前连续 current | 历史最长 best |
|---|---|---|
| 正常 | 1 | 1 |
| 正常 | 2 | 2 |
| 异常 | 0 | 2 |
| 正常 | 1 | 2 |
异常只清零 current,best 保留。更新 best 时比较“已有记录”和“这一段”,不能无条件用 current 覆盖 best。样例边界 140 90 属于正常。
已通过提交中的方法对照
通过提交中可见 if current > best 更新,或 best = max(best, current)。两者等价;后者短一些,前者更直观地展示何时更新历史记录。
保存历史最长的两种局部写法:
python
if current > best:
best = current
# 等价写法
best = max(best, current)不能写成 best = current,否则短的新段会覆盖旧的长记录。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
08 · 找出全部子串位置
90 次未通过,包括 3 次超时、4 次超内存。先检查读入、循环位置是否前进,再检查分隔与换行;判题状态本身不能证明隐藏数据上的具体根因。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| find 返回值、非重叠扫描、循环推进、每组重置和换行 | 第2章第27、31、34–35页;第3章第17–19页 | 先检查读入、循环位置是否前进,再检查分隔与换行;判题状态本身不能证明隐藏数据上的具体根因。 |
提交中出现的错误与定位
错误写法 1:本该同一行,却分两行读取
python
s1 = input()
s2 = input()定位与修改: 本题每组两个字符串在同一行,应一次读取并 split。3 条 TLE、4 条 MLE 提交都出现了这种布局错误;若错读到空目标串,长度为 0,还可能导致扫描位置不前进。这是可构造的风险,不是已知隐藏测试。
错误写法 2:找到后只向后移一位
python
start = position + 1定位与修改: 目标串长度可能大于 1。aaaa 查找 aa 应得到 0 2,向后移一位会多出重叠位置 1;下一起点应是 position + len(s2)。
错误写法 3:用旧起点而不是匹配位置推进
python
start = start + len(s2)定位与修改: xxabxxab 中第一次匹配在 2;如果起点只从 0 加到 2,就会再次找到同一次匹配。应从这次实际找到的位置向后跳。
错误写法 4:结果间无分隔,或组与组之间没有换行
python
print("".join(map(str, positions)))定位与修改: 位置 0、2 应显示 0 2,不是 02。可用空格连接;若逐项 print(..., end=" "),必须在本组结束时补一次换行。没找到时只输出一行 no,避免另加空行。
错误写法 5:在 for 循环中改变量,以为能跳过下次迭代
python
for i in range(len(s1)):
if s1[i:i + len(s2)] == s2:
i += len(s2)定位与修改: 下轮 i 仍由 range 提供,修改 i 不会改变后续取值。需要手动控制步长时改用 while;匹配时跳整个子串,不匹配时只移动一位。
课堂推演与自测
| s1 | s2 | 应输出 |
|---|---|---|
aaaa | aa | 0 2 |
xxabxxab | ab | 2 6 |
abc | z | no |
ab | ab | 0 |
find() 返回 0 表示在开头找到,返回 -1 才表示找不到。每组的起点与结果要重新初始化。这个“不重叠”规则会直接用在本周 py4 的删除子串题。
已通过提交中的方法对照
通过提交中主要有 find(s2, start) 查找和切片逐位置扫描两种方法。前者由 find 找下一处,后者自己控制匹配与不匹配时的步长;两者都须维护原串下标。
找到匹配时的局部对照:
python
# find 返回实际匹配位置 position
start = position + len(target)
# 若自己逐位置扫描,并且在 i 处匹配
i += len(target)逐位置扫描在“不匹配”时只能移动一位。两种方法都要保证每轮能够前进或退出。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
09 · 打印数字三角形
81 次未通过,其中 58 次 PE。数字序列对了,还必须保证行首空格、数字间隔和换行对。
知识点与 PPT
| 知识点 | PPT 位置 | 要讲清什么 |
|---|---|---|
| 行号、range 终点、嵌套循环、行首空格与 sep/end | 第2章第27、36–40页;第3章第16、18、26–27页 | 数字序列对了,还必须保证行首空格、数字间隔和换行对。 |
提交中出现的错误与定位
错误写法 1:只打印数字,没有行首空格
python
print(numbers)定位与修改: 每行由“左侧空格+数字串”组成,不能把所有行贴左输出。第 i 行(从 1 开始)左侧空格数是 n-i。
错误写法 2:把空字符串当空格
python
prefix = "" * (n - i)定位与修改: 空字符串重复多少次仍为空。空格是 " ",空字符串是 ""。
错误写法 3:数字之间加了空格,或 print 又补了一个空格
python
numbers = " ".join(digits)
print(prefix, numbers)定位与修改: 数字之间题目要求没有空格,应使用空串连接;print(prefix, numbers) 默认 sep 也会再加空格,可改成拼接后一次输出或明确 sep=""。
错误写法 4:一基行号和零基行号公式混用
python
for i in range(1, n + 1):
numbers = range(1, 2 * i + 2)定位与修改: 行号从 1 开始时,第 i 行最后一个数字是 2i-1,range 的终点应为 2i。若从 0 开始,公式需要整体对应调整,不要混用。
课堂推演与自测
以 n=4、第 i 行从 1 开始:
| i | 左侧空格数 n-i | 最后一个数字 2*i-1 | 用 · 表示空格的示意 |
|---|---|---|---|
| 1 | 3 | 1 | ···1 |
| 2 | 2 | 3 | ··123 |
| 3 | 1 | 5 | ·12345 |
| 4 | 0 | 7 | 1234567 |
实际输出使用普通空格,不输出 ·。repr(line) 可在本地检查空格,但提交时不要打印 repr:引号也会成为输出内容。
已通过提交中的方法对照
通过提交中有先拼接数字串再补左空格、内层循环用 end="" 逐个输出的写法。课堂优先把空格数与数字范围分开计算。
同一行内连续输出的局部写法:
python
print(prefix, end="")
# 内层循环每次输出一个数字时使用 end=""
# 本行全部输出结束后用 print() 换行先拼好整行再输出也可以。行首空格数和数字范围必须相同,不能因为输出方式不同而改变形状。
完整参考答案
本题答案暂未公开
北京时间 2026/10/16 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
二、py4 本周提示
这部分沿用作业 4 的详细提示,课堂先讲函数、循环与字符串操作,再逐题对照。完整答案保留原加密方式。
01 · 数列求和
解题提示
本题知识点: 第 2 章《基本数据类型》: 用 / 计算倒数,用 f 字符串控制小数位数;第 3 章《程序控制结构与异常处理》: range() 的起点、终点与步长,循环累加;第 4 章《函数》: 定义函数、传入参数、用 return 返回结果。
- 先列出需要哪些分母:
n=8时是2、4、6、8,n=9时是1、3、5、7、9。每项都是“1 除以当前分母”,相邻分母相差 2。 - 把求和过程写入函数。函数接收
n,在内部初始化累计值,逐项相加,最后把总和返回给调用处。 - 主程序负责读入整数、调用函数和输出;只在最后输出时保留 6 位小数。
分母关键点:先确定循环会取到哪些数。 range(start, stop, step) 包含起点、不包含终点,第三个参数表示每次增加多少。例如:
python
list(range(2, 9, 2)) # [2, 4, 6, 8]
list(range(1, 10, 2)) # [1, 3, 5, 7, 9]这里 list() 只是为了观察 range() 生成的数,正式求和时直接用 for 遍历即可。以下两种分母遍历方式任选一种。
方法一:按奇偶性确定起点,正向遍历
偶数从 2 开始,奇数从 1 开始;因为需要包含 n,终点写成 n + 1。
python
if n % 2 == 0:
start = 2
else:
start = 1
# range(start, n + 1, 2) 给出本题需要的全部分母例如 n=8,依次取到 2、4、6、8;下一项 10 已超过终点,循环结束。
方法二:从 n 开始,每次减 2
与 n 同奇偶的数减去 2 后仍保持奇偶性,因此也可以从后往前取分母:
python
list(range(8, 0, -2)) # [8, 6, 4, 2]
list(range(9, 0, -2)) # [9, 7, 5, 3, 1]终点 0 不会被取到,既能保留最后的 1 或 2,也能避免除以零。这种方式不用另写奇偶分支。
累加关键点:每轮保留之前的结果,再加上当前一项。 假设当前分母是 denominator:
python
total += 1 / denominator这相当于 total = total + 1 / denominator。以 n=6、正向遍历为例:
| 当前分母 | 本轮增加 | 累计值 |
|---|---|---|
| 尚未开始 | — | 0 |
| 2 | 1 / 2 | 0.5 |
| 4 | 1 / 4 | 0.75 |
| 6 | 1 / 6 | 约 0.9166667 |
total 应在循环开始前初始化一次。如果每轮都重新赋值为 0,之前加过的数就丢失了。
函数关键点:return 把结果交回调用处。 可以按下面的框架组织,补全中间的求和过程:
python
def seriesSum(n):
total = 0.0
# 在这里遍历分母,把每项累加到 total
return totalreturn total 与循环语句处于同一级缩进,应在所有项加完后执行。若缩进到循环内部,第一次累加后函数就结束了。函数中只 print(total) 而不 return,调用者拿到的会是 None。
输出格式可单独练习:f'{0.5:.6f}' 得到字符串 0.500000。这与 round(0.5, 6) 得到数值 0.5 不同;本题要求显示足够的小数位。
易错点
- 漏掉最后一项:
range(start, n, 2)不包含n;正向遍历时应检查终点设置。 - 把除法写成整除:
1 // denominator会舍去小数部分;这里需要/。 - 累加量反复清零: 初始化在循环外;每轮使用累加,不能直接用当前一项覆盖总和。
- 提前返回或只打印不返回: 检查
return的缩进,以及主程序接收到的是否为数值。 - 过早舍入: 不要每算一项就保留 6 位小数,累计误差可能改变最后结果;统一在输出时格式化。
可用 n=1 → 1.000000、n=2 → 0.500000、n=6 → 0.916667 自测,再检查题面两组样例。
本题答案暂未公开
北京时间 2026/10/27 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
02 · 删除子串
解题提示
本题知识点: 第 2 章《基本数据类型》: split() 拆分输入、in 判断子串、replace() 替换字符串;第 3 章《程序控制结构与异常处理》: 先判断是否存在,再按模式分支;第 4 章《函数》: 接收多个参数并返回字符串。
- 三项数据在同一行:前两项保留为字符串,第三项转成整数。不要对长串、短串进行数值转换。
- 先判断短串是否在原长串中。没有出现时返回题目指定的
Fail to delete;出现时再判断删除模式。 - 模式 0 只处理最左边的一次匹配,模式 1 处理全部不重叠匹配。把处理后的字符串作为函数返回值,由主程序统一输出。
输入关键点:只转换模式。
python
long_str, short_str, mode = input().split()
mode = int(mode)函数可以接收这三个值,例如定义成 strFindDel(long_str, short_str, mode)。函数返回的无论是处理结果还是失败提示,都是字符串。
删除关键点:用空字符串替换子串。 s.replace(old, new, count) 的含义是:在 s 中把 old 换成 new,最多替换 count 次;省略第三个参数时替换全部不重叠匹配。
用一个小例子观察各参数的作用:
python
text = "ab12ab"
text.replace("ab", "X", 1) # "X12ab":只替换最左边一次
text.replace("ab", "", 1) # "12ab":用空串替换,即删除一次
text.replace("ab", "") # "12":删除全部不重叠匹配这些表达式返回新字符串,不会改变原变量 text。要保存结果,就赋值给变量;要把结果交给调用者,就使用 return。
| 输入模式 | 题目含义 | 对应的替换次数 |
|---|---|---|
0 | 至多删除一次 | 第三个参数为 1 |
1 | 删除全部 | 省略第三个参数 |
因此,模式的值不是替换次数。如果直接把 mode 作为第三个参数,模式 0 会变成“一次也不替换”,模式 1 又会变成“只替换一次”。
不重叠关键点:按原串从左到右扫描,匹配过的字符不再重复使用。 这与作业 3 的“找出全部子串位置”采用同样的跳过规则。
样例 aaababbaaa 可以按扫描结果分成:
text
[aa] + ababb + [aa] + a删除方括号内的两段,剩下 ababb + a,即 ababba。不能把前三个 a 中相互重叠的两个 aa 都删除。
还要区分“删除原串中的全部匹配”和“删到再也找不到为止”:
text
原串:a + [aba] + ba
删除原有匹配后:aba对于 aababa 删除 aba,结果仍是 aba。留下的这个 aba 是删除后拼接形成的,不应重新从头继续删除。直接用一次 replace() 符合题意;反复 while short_str in result 会把结果错误地删空。
失败与空结果不同: abc 中删除 abc 是成功删除,结果为空串,应输出一个空行;abc 中查找 z 才属于失败。因此是否失败应在删除前根据原串判断,不能用结果是否为空来判断。
易错点
- 模式与次数混淆: 模式 0 对应删除一次,模式 1 对应删除全部,需先分支再调用替换方法。
- 没有接住新字符串: 单独调用
s.replace(...)后继续输出s,会仍然输出原串。 - 反复删除新形成的子串: 本题只对原串从左向右做不重叠匹配;用
aababa aba 1检查,结果应为aba。 - 把空串当作失败:
abc abc 0应输出空行,不能输出Fail to delete。 - 失败文字不一致: 大小写、单词间空格都需保持
Fail to delete;不要增加引号或中文说明。
可补测 aaaa aa 0 → aa、aaaa aa 1 → 空串、aaa aa 1 → a,对照一次删除、全部删除和不重叠规则。
本题答案暂未公开
北京时间 2026/10/27 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
03 · 机器猜数
解题提示
本题知识点: 第 2 章《基本数据类型》: 整除与向上取整;第 3 章《程序控制结构与异常处理》: while 循环、条件分支、计数和 break。本题使用“每次排除一半候选数”的二分思路。
- 维护两个变量
left、right,表示当前仍可能包含目标的范围,初始为 1 和 100;另设计数器,初始为 0。 - 只要范围内仍有至少两个候选数,就取中点猜一次,并把次数加一。中点必须按题意向上取整。
- 比较中点与目标:相等就停止;猜大了保留左侧,猜小了保留右侧。两种情况下都要排除本轮已经猜过的中点。
- 如果范围只剩一个数,可以直接确定目标,不再猜一次,也不再增加计数。
中点关键点:普通的整除会向下取整。 本题的端点都是整数,可以用“先加 1,再整除 2”得到向上取整的平均值:
python
middle = (left + right + 1) // 2| 当前范围 | 平均值 | 本题应猜 | (left + right) // 2 会得到 |
|---|---|---|---|
[1, 100] | 50.5 | 51 | 50 |
[1, 4] | 2.5 | 3 | 2 |
[1, 5] | 3 | 3 | 3 |
端点和为奇数时,加 1 能补足半个整数;端点和为偶数时,加 1 后再整除仍得到原来的整数平均值。也可用 math.ceil((left + right) / 2);不要用 round() 代替向上取整。
区间更新关键点:已经猜过的中点不再保留。
| 比较结果 | 下一步 | 原因 |
|---|---|---|
middle == n | 本轮计数后结束 | 已猜中 |
middle > n | right = middle - 1 | 目标严格小于中点 |
middle < n | left = middle + 1 | 目标严格大于中点 |
不能只写 left = middle 或 right = middle:这会把已经排除的数继续留在范围里,有时还会让范围无法缩小。
计数关键点:猜中和“只剩一个候选数”是两种结束方式。 用样例 n=5 逐轮检查:
| 第几次猜测 | 猜测前的范围 | 向上取整的中点 | 与 5 比较 | 下一范围 |
|---|---|---|---|---|
| 1 | [1, 100] | 51 | 猜大了 | [1, 50] |
| 2 | [1, 50] | 26 | 猜大了 | [1, 25] |
| 3 | [1, 25] | 13 | 猜大了 | [1, 12] |
| 4 | [1, 12] | 7 | 猜大了 | [1, 6] |
| 5 | [1, 6] | 4 | 猜小了 | [5, 6] |
| 6 | [5, 6] | 6 | 猜大了 | [5, 5] |
最后虽然没有把中点猜成 5,但范围已是 [5,5],可以直接确定目标,所以答案是 6 次。若写成 while left <= right,就容易在最后多猜一次;本题应只在 left < right 时继续猜。
另一方面,n=51 第一次就猜中,答案是 1,不能因为相等就先退出、漏记本轮。安排语句时可按“计算中点 → 次数加一 → 比较并更新”的顺序。
易错点
- 使用向下取整的中点: 第一次必须猜 51;猜 50 就已经偏离题目规则。
- 把单元素区间也算一次:
[5,5]无需猜测,计数不会再增加。 - 猜中这一轮没有计数: 次数加一应在退出前完成;用
n=51检查。 - 更新方向颠倒: 猜大了缩小右端点,猜小了增大左端点,且都排除中点。
- 把“随机选择”理解为随机生成: 目标数由输入提供,不需要
random;程序模拟的是给定规则。
除样例外,可检查 n=26 → 2、n=1 → 6、n=100 → 6,覆盖提前猜中及范围两端。
本题答案暂未公开
北京时间 2026/10/27 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
04 · 自动判题
解题提示
本题知识点: 第 2 章《基本数据类型》: split() 拆分字符串、float() 转换数字、round() 保留小数位;第 3 章《程序控制结构与异常处理》: 根据运算符选择分支、根据比较结果输出指定字符串。
- 先把一行沿等号分成“待计算的表达式”和“给定结果”。给定结果只需转成数值;左侧还要拆出两个操作数和运算符。
- 题目保证左侧两个数非负,可以在左侧依次检查
+、-、*、/,找到运算符后按它拆分。 - 将两个操作数转成浮点数,按运算符执行计算。再将计算值保留两位小数,与右侧的数值比较。
- 比较成立时输出小写
true,不成立时输出小写false。
拆分关键点:先拆等号,再处理左侧。 可先用固定字符串练习:
python
expression, expected_text = "1.57-5.33=-1.51".split("=")
# expression 是 "1.57-5.33"
# expected_text 是 "-1.51"右侧结果可能带负号。如果直接对整行按 - 拆分,会把右侧负号也拆掉。先沿等号分开,就能把“左侧减法运算符”和“右侧负数符号”区分开。
对于左侧,可把“查找运算符”单独写成一小段:
python
for operator in "+-*/":
if operator in expression:
left_text, right_text = expression.split(operator)
break找到后,left_text、right_text 仍是字符串,需分别转成 float。这个拆分方法依赖题面“左侧两个数非负”的条件,不能直接套到任意复杂表达式上。
运算关键点:变量里的符号不会自动变成运算。 当 operator 的值为 "*" 时,Python 不会自动把它当作乘号执行;用 if/elif 选择真正的运算。例如加法分支可以写成:
python
if operator == "+":
calculated = left_number + right_number其余三个分支按对应运算补齐即可。此时两侧操作数已经是浮点数,+ 才表示数值相加,而不是字符串拼接。
精度关键点:先保留两位小数,再比较。
| 输入等式 | 左侧计算值 | 保留两位后的数值 | 右侧数值 | 应输出 |
|---|---|---|---|---|
2.1*4=8.40 | 8.4 | 8.4 | 8.4 | true |
1/3=0.33 | 约 0.333333… | 0.33 | 0.33 | true |
1.57-5.33=-1.51 | 约 -3.76 | -3.76 | -1.51 | false |
第一行中的 8.4 和 8.40 表示同一个数。不能直接比较它们的字符串形式,也不能不做小数位处理就比较 1/3 与 0.33。
可以先独立观察这个局部过程:
python
rounded_value = round(1 / 3, 2) # 0.33
expected_value = float("0.33")参考解法在舍入后用 math.isclose(rounded_value, expected_value) 比较。这一函数返回布尔值,使用前需 import math;最后仍需把布尔判断映射成题目要求的小写单词。
round() 和固定两位小数的格式化有什么区别?
python
round(8.4, 2) # 数值 8.4
f'{8.4:.2f}' # 字符串 "8.40"round() 返回可继续计算和比较的数值;f 字符串控制显示形式,返回字符串。本题最终只输出 true 或 false,所以不必把中间计算值输出成两位小数。
Python 的 round() 在恰好位于中间的情况采用向偶数舍入,例如 round(0.125, 2) 为 0.12;浮点数本身也可能存在表示误差。不要自行给所有结果加上 0.005,尤其负数时不能这样处理。
易错点
- 整行按减号拆分: 右侧可能是负数;先拆等号,再找左侧运算符。
- 忘记类型转换:
"2.1" + "4"得到字符串"2.14",不是数值加法。 - 没有先舍入: 直接比较原始计算值,会把
1/3=0.33错判为不成立;math.isclose()也不能替代保留两位小数这一步。 - 把比较变成“差小于一分钱”: 两个不同的两位小数结果不应因为人为放宽容差而被当成相等,例如
2.1*4=8.41应为false。 - 输出布尔值本身:
print(True)输出的是大写开头的True;题目要求小写true、false。
可再用 0.1+0.2=0.30、1-2=-1.00 检查浮点数加法和负结果,两者均应输出 true。
本题答案暂未公开
北京时间 2026/10/27 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…
05 · 凯撒密码
解题提示
本题知识点: 第 2 章《基本数据类型》: ord()、chr()、取余与字符串拼接;第 3 章《程序控制结构与异常处理》: 模式判断、字符分类和逐字符循环;第 4 章《函数》: 把重复的字符转换步骤封装为函数。
- 按三行读取模式、密钥、消息。模式先与题面列出的字符串比较,无效时输出
Wrong Mode;有效时确定是向加密方向移动还是向解密方向移动。 - 逐个处理消息中的字符:大写字母、小写字母、数字分别转换;空格、标点等其他字符原样保留。
- 对需要转换的字符,先算它在所属字符组中的位置,再移动、取余、转换回字符。把这段共用过程写成函数。
- 按原顺序拼接每个转换结果,最后只输出完整消息。
与作业 2 的联系:从“一个小写字母”扩展到“一整行、多种字符和解密”。 作业 2 的字母加密使用 26 个小写字母组成的环;本题需要区分三个独立的环:
| 字符类别 | 范围判断示例 | 起点字符 | 位置范围 | 环的长度 |
|---|---|---|---|---|
| 大写字母 | 'A' <= ch <= 'Z' | 'A' | 0~25 | 26 |
| 小写字母 | 'a' <= ch <= 'z' | 'a' | 0~25 | 26 |
| 数字字符 | '0' <= ch <= '9' | '0' | 0~9 | 10 |
| 其他字符 | 不属于上述三类 | — | — | 原样保留 |
例如 '0' 是字符,0 是整数;ord('0') 得到字符编码,不是整数 0。先减去所在组起点的编码,才能得到从 0 开始的位置。
转换关键点:减起点、移动、取余、加回起点。 以下片段只演示一个小写字符如何绕过末尾:
python
ch = 'z'
base = ord('a')
position = ord(ch) - base # 25
new_position = (position + 3) % 26 # 2
new_char = chr(base + new_position) # 'c'ord() 将字符转成编码;chr() 将编码转回字符。不能直接对 ord(ch) + key 取余后调用 chr(),因为余数是环内位置,还没有加回字符组起点。
解密关键点:沿同一个环向反方向移动。 加密用 +key,解密用 -key,因此可先根据模式把“移动量”设成正数或负数,后续转换过程共用。
以密钥 3 解密小写字母 b 为例:
text
b 的位置为 1
向前退 3 步:1 - 3 = -2
回到 26 个位置的环中:(-2) % 26 = 24
位置 24 对应 yPython 对正整数 26 取余时,结果会落在 0~25,负的移动位置也能自动绕回。无需为越过 'a' 再写一套特殊分支。
| 操作 | 环内计算 | 转换结果 |
|---|---|---|
z 加密,密钥 3 | (25 + 3) % 26 = 2 | c |
b 解密,密钥 3 | (1 - 3) % 26 = 24 | y |
8 加密,密钥 15 | (8 + 15) % 10 = 3 | 3 |
3 解密,密钥 15 | (3 - 15) % 10 = 8 | 8 |
数字一行尤其值得检查:密钥 15 超过数字环长 10,但取余仍能处理;不能对数字也使用 % 26。
函数关键点:把变化的部分作为参数。 三种字符组使用同一种转换过程,区别只是起点和环长。可设计一个接收“字符、移动量、起点字符、环长”的函数:
python
def transform(ch, shift, base_char, cycle_length):
# 求 ch 相对 base_char 的位置
# 移动 shift 步,并对 cycle_length 取余
# 转回字符后 return
pass这里的 pass 是待补全的占位语句。函数每次返回一个字符;主程序判断字符类别后传入对应的起点和长度。对其他字符则直接保留,不必送入转换函数。
输入与拼接关键点:保留消息中的空格。 消息行使用 input() 整行读取,不要 split(),也不要为了“清理输入”随意删掉首尾空格。循环中可以先用最直接的字符串累加方式理解:
python
result = ""
# 每得到一个 converted_char,就接到当前结果后面:
# result += converted_char参考解法用列表收集字符,最后 ''.join(...) 拼接,作用相同。循环中逐字符 print() 会多出换行,不符合整行输出要求。
样例密钥为 23:大写 I 的位置是 8,(8+23)%26=5,得到 F;数字 1 变成 (1+23)%10=4。所以样例开头的 I 变为 F,编号 19123 变为 42456,空格和句点保留。
易错点
- 合法模式扩大或漏写: 题面列出
e、E、encrypt、Encrypt和对应四种解密模式;ENCRYPT不在列表中,应为Wrong Mode,不能无条件转小写后接受。 - 三类字符混用一个环: 大写、小写分别保持大小写,数字按 10 循环,不能全部使用起点
'a'或长度 26。 - 编码与位置混淆: 取余前减去起点编码,取余后加回起点编码,再调用
chr()。 - 解密仍向加密方向移动: 解密应减去密钥;可用上表的
b → y检查。 - 空格、标点被删除或改变: 消息作为整行读取,其他字符原样接入结果。使用明确的英文字母和数字范围也可避免把中文、全角数字误当作待转换字符。
可测试加密模式、密钥 1、消息 Az9!,应得到 Ba0!;再用同一密钥解密 Ba0!,应回到 Az9!。两次检查能同时覆盖大小写、数字环绕和标点保留。
本题答案暂未公开
北京时间 2026/10/27 13:00:00 解锁
正在检查解锁状态…
正在载入加密答案…