Skip to content

2026-计算概论C-py作业4 ​

题集链接 ​

OpenJudge/计算概论C(py)/2026-计算概论C-py作业4

共 5 题。题面、知识点、解题提示和易错点可直接查看;完整参考解析于北京时间 2026-10-27 13:00 截止后公开,教师可用作业 2 的密码提前查看。

01:数列求和 ​

题目描述 ​

对数列进行求和。给定一个整数 n,当 n 为偶数时,计算 1/2 + 1/4 + ...... + 1/n 的和;当 n 为奇数时,计算 1/1 + 1/3 + ...... + 1/n 的和。

要求使用函数实现。

输入

一个整数 n (0 < n <= 1000)

输出

一个浮点数表示数列的和,保留 6 位小数

样例输入

text
# 样例 1
8

# 样例 2
9

样例输出

text
# 样例 1
1.041667

# 样例 2
1.787302

样例中的 # 样例 为分组标签,每组需独立运行,标签本身不属于输入。

解题提示

本题知识点: 第 2 章《基本数据类型》: 用 / 计算倒数,用 f 字符串控制小数位数;第 3 章《程序控制结构与异常处理》: range() 的起点、终点与步长,循环累加;第 4 章《函数》: 定义函数、传入参数、用 return 返回结果。

  1. 先列出需要哪些分母:n=8 时是 2、4、6、8,n=9 时是 1、3、5、7、9。每项都是“1 除以当前分母”,相邻分母相差 2。
  2. 把求和过程写入函数。函数接收 n,在内部初始化累计值,逐项相加,最后把总和返回给调用处。
  3. 主程序负责读入整数、调用函数和输出;只在最后输出时保留 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
21 / 20.5
41 / 40.75
61 / 6约 0.9166667

total 应在循环开始前初始化一次。如果每轮都重新赋值为 0,之前加过的数就丢失了。

函数关键点:return 把结果交回调用处。 可以按下面的框架组织,补全中间的求和过程:

python
def seriesSum(n):
    total = 0.0
    # 在这里遍历分母,把每项累加到 total
    return total

return 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:删除子串 ​

题目描述 ​

有两个非空字符串,一个长的字符串,一个短的字符串。现在要在长串中查找并删除短串,打印处理后的结果。一个额外的参数表示全部删除子串或者至多删除一次。查找时从左到右查找,找到的子串不允许重叠(参见样例3)。

要求使用函数实现。

输入

输入只有一行,共三项,用空格隔开。前两个是字符串,分别是长字符串和短字符串。前者长度大于等于后者的长度,且字符串中不包含空白符。还有一个整数 n,取值为 0 或 1,0 表示至多删除一次,1 表示全部删除。

输出

如果短串包含在长串中,则打印处理后的字符串,否则打印 "Fail to delete"

样例输入

text
# 样例 1
abcdeabcde fg 0

# 样例 2
abcdeabcde ab 1

# 样例 3
aaababbaaa aa 1

样例输出

text
# 样例 1
Fail to delete

# 样例 2
cdecde

# 样例 3
ababba

样例中的 # 样例 为分组标签,每组需独立运行,标签本身不属于输入。

解题提示

本题知识点: 第 2 章《基本数据类型》: split() 拆分输入、in 判断子串、replace() 替换字符串;第 3 章《程序控制结构与异常处理》: 先判断是否存在,再按模式分支;第 4 章《函数》: 接收多个参数并返回字符串。

  1. 三项数据在同一行:前两项保留为字符串,第三项转成整数。不要对长串、短串进行数值转换。
  2. 先判断短串是否在原长串中。没有出现时返回题目指定的 Fail to delete;出现时再判断删除模式。
  3. 模式 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:机器猜数 ​

题目描述 ​

随机选择 1 ~100 的一个整数 n,通过某种规则判断这个数 n 是多少。

规则如下:给定当前的数字范围[a, b],选择其中间的数 m=(a+b)/2,判断 m 和 n 的大小关系。如果 m = n,则表示猜对了,如果 m > n,则在 [a, m-1] 中继续判断,如果 m < n,则在 [m+1, b] 中继续判断。如果数字范围 [a, b] 的中间数 m 不是整数,则向上取整,例如 [1, 4],则 m = 3。如果数字范围满足 a = b,那么数 n 一定满足 n = a = b,此时不需要继续猜数。

初始的数字范围是 [1, 100]。现在有一个猜数机器,按照上述的规则进行猜数,那么这个猜数机器需要猜几次?

输入

一个整数,范围是 1 ~ 100(包含1和100)

输出

一个整数,表示按照题目的规则猜数,猜对结果时总共猜数的次数。

样例输入

text
# 样例 1
5

样例输出

text
# 样例 1
6

样例中的 # 样例 为分组标签,每组需独立运行,标签本身不属于输入。

解题提示

本题知识点: 第 2 章《基本数据类型》: 整除与向上取整;第 3 章《程序控制结构与异常处理》: while 循环、条件分支、计数和 break。本题使用“每次排除一半候选数”的二分思路。

  1. 维护两个变量 left、right,表示当前仍可能包含目标的范围,初始为 1 和 100;另设计数器,初始为 0。
  2. 只要范围内仍有至少两个候选数,就取中点猜一次,并把次数加一。中点必须按题意向上取整。
  3. 比较中点与目标:相等就停止;猜大了保留左侧,猜小了保留右侧。两种情况下都要排除本轮已经猜过的中点。
  4. 如果范围只剩一个数,可以直接确定目标,不再猜一次,也不再增加计数。

中点关键点:普通的整除会向下取整。 本题的端点都是整数,可以用“先加 1,再整除 2”得到向上取整的平均值:

python
middle = (left + right + 1) // 2
当前范围平均值本题应猜(left + right) // 2 会得到
[1, 100]50.55150
[1, 4]2.532
[1, 5]333

端点和为奇数时,加 1 能补足半个整数;端点和为偶数时,加 1 后再整除仍得到原来的整数平均值。也可用 math.ceil((left + right) / 2);不要用 round() 代替向上取整。

区间更新关键点:已经猜过的中点不再保留。

比较结果下一步原因
middle == n本轮计数后结束已猜中
middle > nright = middle - 1目标严格小于中点
middle < nleft = 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:自动判题 ​

题目描述 ​

自动判断一个简单的数学等式是否成立。这里的数学等式是两个数的四则运算(加,减,乘,除)。参与运算的数是浮点数,结果保留两位小数。

输入

一个等式。数字和运算符之间没有空格。等式左边的两个数是非负数,右边的结果仅仅保留两位小数。

输出

一个字符串,true 或者 false

样例输入

text
# 样例 1
2.1*4=8.40

# 样例 2
1/3=0.33

# 样例 3
1.57-5.33=-1.51

样例输出

text
# 样例 1
true

# 样例 2
true

# 样例 3
false

样例中的 # 样例 为分组标签,每组需独立运行,标签本身不属于输入。

解题提示

本题知识点: 第 2 章《基本数据类型》: split() 拆分字符串、float() 转换数字、round() 保留小数位;第 3 章《程序控制结构与异常处理》: 根据运算符选择分支、根据比较结果输出指定字符串。

  1. 先把一行沿等号分成“待计算的表达式”和“给定结果”。给定结果只需转成数值;左侧还要拆出两个操作数和运算符。
  2. 题目保证左侧两个数非负,可以在左侧依次检查 +、-、*、/,找到运算符后按它拆分。
  3. 将两个操作数转成浮点数,按运算符执行计算。再将计算值保留两位小数,与右侧的数值比较。
  4. 比较成立时输出小写 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.408.48.48.4true
1/3=0.33约 0.333333…0.330.33true
1.57-5.33=-1.51约 -3.76-3.76-1.51false

第一行中的 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:凯撒密码 ​

题目描述 ​

对字母和数字进行加密和解密。密钥是一个数字,用于加密和解密。

要求使用函数实现。

输入

输入有三行,每行一项,分别是模式、密钥、需要处理的信息。 第一行为模式,可能是 e, E, encrypt, Encrypt (这四个表示加密), d, D, decrypt, Decrypt (这四个表示解密), 或者是其他字符串。 第二行为密钥,是一个大于 0 且小于等于 26 的整数。 第三行为需要处理的信息,是一个字符串。

输出

如果模式表示加密或解密,则输出一个字符串,表示加密信息或解密信息。 如果模式既不是加密或解密,那么不论密钥和需要处理的信息是什么,都输出 "Wrong Mode"。

样例输入

text
e
23
I am a student. My ID is 19123.

样例输出

text
F xj x pqrabkq. Jv FA fp 42456.

解题提示

本题知识点: 第 2 章《基本数据类型》: ord()、chr()、取余与字符串拼接;第 3 章《程序控制结构与异常处理》: 模式判断、字符分类和逐字符循环;第 4 章《函数》: 把重复的字符转换步骤封装为函数。

  1. 按三行读取模式、密钥、消息。模式先与题面列出的字符串比较,无效时输出 Wrong Mode;有效时确定是向加密方向移动还是向解密方向移动。
  2. 逐个处理消息中的字符:大写字母、小写字母、数字分别转换;空格、标点等其他字符原样保留。
  3. 对需要转换的字符,先算它在所属字符组中的位置,再移动、取余、转换回字符。把这段共用过程写成函数。
  4. 按原顺序拼接每个转换结果,最后只输出完整消息。

与作业 2 的联系:从“一个小写字母”扩展到“一整行、多种字符和解密”。 作业 2 的字母加密使用 26 个小写字母组成的环;本题需要区分三个独立的环:

字符类别范围判断示例起点字符位置范围环的长度
大写字母'A' <= ch <= 'Z''A'0~2526
小写字母'a' <= ch <= 'z''a'0~2526
数字字符'0' <= ch <= '9''0'0~910
其他字符不属于上述三类——原样保留

例如 '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 对应 y

Python 对正整数 26 取余时,结果会落在 0~25,负的移动位置也能自动绕回。无需为越过 'a' 再写一套特殊分支。

操作环内计算转换结果
z 加密,密钥 3(25 + 3) % 26 = 2c
b 解密,密钥 3(1 - 3) % 26 = 24y
8 加密,密钥 15(8 + 15) % 10 = 33
3 解密,密钥 15(3 - 15) % 10 = 88

数字一行尤其值得检查:密钥 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 解锁

正在检查解锁状态…

正在载入加密答案…

课程资料由授课教师、助教与同学共同积累。