01 / 本课学习路线
本课学习路线
阅读与推演约 110 分钟,练习约 75 分钟
02 / 学习目标与先修自测
学完本课你能做什么,以及开始前需要会什么
数值题的代码都不长,错误几乎都出在两处:下标对位和数值范围。把「先写形状、再写循环、再查位宽」变成固定顺序。
| 学完后能做的事 | 正文位置 | 检查方式 |
|---|---|---|
| 不看资料写出 (m,k)@(k,n)→(m,n) 的三重循环,下标全部正确 | 第 04、05 节 | 自查第 2 条、代码自测、练习 4 |
| 解释为什么 AI029 的累加必须用 64 位整数 | 第 06 节 | 自查第 3 条 |
| 说出题目给转置矩阵时的两种处理方式 | 第 05 节、补充学习 | 自查第 4 条、练习 2 |
| 动手前先在草稿上写出每个矩阵的维度 | 第 04 节 | 自查第 5 条 |
| 写对 P2475 的三段规则与取整,通过两道必做题 | 第 07、08 节 | 必做任务 1、2 |
先修自测:下面 5 题请先自己写答案,再展开对照。答不出的按括号里的位置补看再回来。本课假定你已完成模块 1 的「二维数组、坐标与边界处理」。
| 题号 | 题目 | 补看位置 |
|---|---|---|
| 自测 1 | C = [[0] * n for _ in range(m)]:C 有几行几列?C[i][j] 里 i 走到哪、j 走到哪? | 二维数组、坐标与边界处理第 03 节 |
| 自测 2 | 先读一行 2 3,再读 2 行、每行 3 个整数:写出读入代码。 | 输入与输出 |
| 自测 3 | sum(a * b for a, b in zip([1, 2, 3], [4, 5, 6])) 是多少? | 常用内置函数 |
| 自测 4 | 84 / 8、84 // 8、math.floor(84 / 8 + 0.5) 各是多少? | 数字与运算符 |
| 自测 5 | abs(10 - 10.5) 是多少?它是整数还是小数? | 数字与运算符 |
展开先修自测答案
自测 1:m 行 n 列;i 走 0..m−1、j 走 0..n−1。矩阵乘的结果 C 就这样建,形状 (m, n)。
自测 2:m, k = map(int, input().split()),然后 A = [list(map(int, input().split())) for _ in range(m)]。本课参考程序一次读完全部整数再按顺序取,效果相同。
自测 3:32——就是行向量 [1,2,3] 点乘列向量 [4,5,6],也是 C[i][j] 的定义。
自测 4:10.5、10、11。// 是向下取整不是四舍五入;「加 0.5 再向下取整」才是四舍五入——P2475 的取整规则。
自测 5:0.5,小数。P2475 的 diff 是小数,和 30、50 比较时不要先取整。
03 / 概念与术语
形状、公共维度、点积、转置、64 位整数
约定记号:A 是 (m,k),B 是 (k,n),乘积 C 是 (m,n)。判断能不能乘只看一件事:A 的列数等于 B 的行数。
| 术语 | 含义 | 代码里的位置 |
|---|---|---|
| 形状 (m, k) | m 行 k 列;先写形状再写循环 | m, k = len(A), len(A[0]) |
| 公共维度 k | A 的列数 = B 的行数;求和沿着它走 | for t in range(k) |
| 点积 | 一行与一列对应位相乘再求和 | s += A[i][t] * B[t][j] |
| 维度不匹配 | k ≠ p:不能乘;题目规定输出什么就输出什么 | if k != p: print("shape mismatch") |
| 转置 Bᵀ | 行列互换,(k,n) 变 (n,k);题目可能直接给它 | 先转回来,或改成「A 的第 i 行 · Bᵀ 的第 j 行」 |
| 64 位整数 | 累加可达 2×10¹⁴,超过 32 位上限 2,147,483,647 | C++ long long、Java long;Python 整数自动扩展 |
| 四舍五入取整 | 加 0.5 后向下取整;语言默认 round 在 .5 处可能取偶数 | floor(x + 0.5) |
补充学习(选学)转置存储怎么识别约 5 分钟题目给的是 Bᵀ 时的两种处理方式
AI 场次的题目常按「每行一个样本、每列一个特征」或反过来给数据,也有题目直接声明给的是 B 的转置。读题时先在草稿上写清楚:输入的第 r 行第 c 列在数学上是谁。
拿到 Bᵀ(形状 (n,k))有两种处理:先转置回 (k,n) 再按标准三重循环乘;或者不转置,把内层点积改成「A 的第 i 行点乘 Bᵀ 的第 j 行」。两种都正确;不要将 Bᵀ 直接当作 B 参与标准矩阵乘法——当 k 恰好等于 n 时(例如 B 是方阵)形状合法、代码不报错,但数值一般都是错的(第 05 节给了 2×2 的例子);k ≠ n 时维度检查会直接拦下它。只有拿手动推演的值逐项核对才能当场发现。
补充学习(选学)矩阵乘的复杂度预算约 4 分钟把 O(m·k·n) 换算成运行时间,并检查 Java 的输出方式
朴素矩阵乘是 O(m·k·n):AI029 最大规模 200³ = 8×10⁶ 次乘加,100³ = 10⁶ 次。这一规模可以用三重循环在 3 秒时限内完成,但具体运行时间与语言和运行环境有关,提交前可用最大规模的输入自测一次。到 500³ = 1.25×10⁸ 的规模,Python 的三重循环就接近时限了——本题的数据范围不会到这一量级。
一个和语言相关的易错点:Java 若在循环里逐元素用字符串拼接输出,200×200 的结果矩阵就可能超时——可使用字符串构建器(StringBuilder)汇总结果后统一输出;Python 用拼接方法(join)拼好后一次输出,道理相同。
04 / 形状规则与逐项表
先核对维度,再逐项计算:(2,3)@(3,2) 的四个元素
AI029「矩阵乘法与维度检查」:第一行两个整数 m k,随后 m 行、每行 k 个整数是矩阵 A;再一行两个整数 p n,随后 p 行、每行 n 个整数是矩阵 B(1 ≤ m, k, p, n ≤ 200,|元素| ≤ 10⁶)。k ≠ p 时只输出一行 shape mismatch;否则输出 C = A × B 的 m 行、每行 n 个整数,单个空格分隔。样例 1 就是下面的 (2,3)@(3,2);样例 2:2 2 / 1 2 / 3 4 / 3 2 / 5 6 / 7 8 / 9 10 → shape mismatch(k = 2、p = 3)。
| 元素 | A 的第 i 行 | B 的第 j 列 | 逐项相乘再求和 | 结果 |
|---|---|---|---|---|
| C[0][0] | [1, 2, 3] | [7, 9, 11] | 7 + 18 + 33 | 58 |
| C[0][1] | [1, 2, 3] | [8, 10, 12] | 8 + 20 + 36 | 64 |
| C[1][0] | [4, 5, 6] | [7, 9, 11] | 28 + 45 + 66 | 139 |
| C[1][1] | [4, 5, 6] | [8, 10, 12] | 32 + 50 + 72 | 154 |
C = [[58, 64], [139, 154]],形状 (2,3)@(3,2) → (2,2)——就是样例 1 的输出 58 64 / 139 154。写完代码后,先拿这四个数做第一组核对。
| 形状组合 | 结果 | 例子 |
|---|---|---|
| (1,k) @ (k,1) | (1,1):行向量点乘列向量,得一个数 | [[1,2,3]] @ [[4],[5],[6]] = [[32]] |
| (m,1) @ (1,n) | (m,n):外积,一列乘一行铺满整个矩阵 | [[2],[3]] @ [[4,5]] = [[8,10],[12,15]] |
| (2,3) @ (2,2) | 不能乘:3 ≠ 2 | 输出 shape mismatch |
| (2,2) @ (3,2) | 不能乘:2 ≠ 3 | 样例 2,输出 shape mismatch |
两种特殊形状按普通矩阵乘处理即可,不需要写特判;维度检查必须在计算前完成,不检查就相乘会在下标上越界(第 09 节错误表)。
05 / 三重循环与下标对位
外两层走 i、j,最内层走公共维度 t;转置输入的两种处理
最内层是 C[i][j] += A[i][t] * B[t][j],t 走 0..k−1。自查一遍:A 的第二个下标和 B 的第一个下标必须都是 t。
下标写错在方阵上不报错、只算错:A = [[1,2],[3,4]]、B = [[5,6],[7,8]]
正确 A[i][t] * B[t][j]:C = [[19, 22], [43, 50]] 写成 A[i][t] * B[j][t](把 B 当成了 Bᵀ):C = [[17, 23], [39, 53]]——形状合法、程序不报错,每个数都错 写成 A[t][i] * B[t][j]:在 (2,3)@(3,2) 上直接下标越界(IndexError) 所以核对用手算表:四个数对上了,下标就对了
| 处理 | 内层写法 | 适用 |
|---|---|---|
| 先转置回 (k,n) | Bt[j][t] 转成 B[t][j] 后照常三重循环 | 想保持标准模板不变 |
| 不转置,行乘行 | s += A[i][t] * Bt[j][t] | 少一次拷贝;模块 7 注意力题的 Q·Kᵀ 就是这种 |
两种都对。错的是「把 Bᵀ 直接当 B」——见上面第二行。
06 / 64 位累加
乘积到 10¹²、200 项累加到 2×10¹⁴:为什么 32 位放不下
AI029 里 |元素| ≤ 10⁶,公共维度最多 200。
| 量 | 最大值 | 与 32 位上限比较 | 与 64 位上限比较 |
|---|---|---|---|
| 单个乘积 | 10⁶ × 10⁶ = 10¹² | > 2,147,483,647 | ≪ 9.22×10¹⁸ |
| 一个 C[i][j](200 项累加) | 2×10¹⁴ | > 2,147,483,647 | ≪ 9.22×10¹⁸ |
| 200 个 10⁶ 组成的行向量点乘同样的列向量 | 2×10¹⁴(2×2 全 10⁶ 的例子已到 2×10¹²) | 溢出 | 放得下 |
Python 整数自动扩展,不会溢出;C++ 用 long long、Java 用 long,从读入那一刻就用对类型——乘法在 32 位里先溢出、再转 64 位已经晚了。
07 / P2475 图像坏点矫正
三段规则各用哪个均值;四舍五入取整用加 0.5 向下取整
P2475「图像坏点矫正」:3 行、每行 3 个 0–255 的整数;diff = |中心 − 周围 8 个的均值|;diff > 50 用周围均值(四舍五入取整)替换中心,30 ≤ diff ≤ 50 用 9 个的整体均值(四舍五入取整)替换,diff < 30 不变;输出矫正后的 3×3。题面示例:10 10 10 / 10 200 10 / 10 10 10 → 中心变 10。
| 输入(中心 / 周围) | 周围均值 | diff | 落在哪段 | 替换值 | 输出中心 |
|---|---|---|---|---|---|
| 200 / 全 10(题面示例) | 10 | 190 | > 50:周围均值 | floor(10 + 0.5) = 10 | 10 |
| 50 / 全 10 | 10 | 40 | 30..50:整体均值 (50 + 80) / 9 = 14.44 | floor(14.44 + 0.5) = 14 | 14 |
| 100 / 七个 10 与一个 14 | 84 / 8 = 10.5 | 89.5 | > 50:周围均值 | floor(10.5 + 0.5) = 11 | 11 |
| 40 / 全 10 | 10 | 30 | 恰好 30:属于 30..50 | floor((40 + 80) / 9 + 0.5) = floor(13.83) = 13 | 13 |
第三行是「均值恰好 .5」:加 0.5 向下取整得 11;Python 的 round(10.5) 按「四舍六入五成双」得 10——题目要求四舍五入,所以不用 round。第四行是区间端点:diff 恰好 30 属于中间段,条件要写 30 <= diff。
两个均值不要混用:周围均值只算 8 个,整体均值算 9 个(周围和 + 中心)。diff 用小数比较,不要先取整。
08 / 从形状到程序
参考实现与完整程序,每一步落在哪几行
先用手动推演的四个数字让 matmul 的断言全部通过,再提交在线题目。
| 步骤 | AI029 | P2475 |
|---|---|---|
| 读入 | m k、A 的 m 行、p n、B 的 p 行 | 3 行各 3 个整数 |
| 检查 | if k != p: print("shape mismatch") | 算 diff 后分三段 |
| 核心循环 | for i / for j / for t: s += A[i][t] * B[t][j] | 周围 8 个求和:跳过 (1,1) |
| 取整 / 位宽 | Python 整数不溢出;C++/Java 用 64 位 | floor(x + 0.5) |
| 输出 | m 行,每行 n 个整数空格分隔 | 3 行,每行 3 个整数 |
矩阵乘法三重循环模板(matmul)
Pythonimport sys
def matmul(A, B):
m, k = len(A), len(A[0])
p, n = len(B), len(B[0])
# 待完成 1:维度检查——k != p 时按题目要求输出 shape mismatch 并返回
C = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
# 待完成 2:遍历公共维度 t = 0..k-1,累加 A[i][t] * B[t][j]
pass
return C
def main():
data = sys.stdin.buffer.read().split()
# 待完成 3:按题目说明的顺序读入 m k、矩阵 A、p n、矩阵 B
...
main()写完自查一遍下标对位:A 的第二个下标和 B 的第一个下标必须都是累加变量 t——若有一处未对应同一个累加维度,可能出现维度不匹配或计算结果错误。
展开参考实现:matmul(自带断言;先自己写完再对照)
matmul 的参考实现(自带断言)
Pythondef matmul(A, B):
m, k = len(A), len(A[0])
p, n = len(B), len(B[0])
if k != p: # 中间维度不相等:不能乘
return None
C = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
s = 0
for t in range(k): # A 的第二个下标、B 的第一个下标都是 t
s += A[i][t] * B[t][j]
C[i][j] = s
return C
A = [[1, 2, 3], [4, 5, 6]]
B = [[7, 8], [9, 10], [11, 12]]
assert matmul(A, B) == [[58, 64], [139, 154]] # 第 04 节四个元素
assert matmul([[1, 2, 3]], [[4], [5], [6]]) == [[32]] # 行向量 · 列向量 → 1×1
assert matmul([[2], [3]], [[4, 5]]) == [[8, 10], [12, 15]] # 外积 → 2×2
assert matmul(A, [[1, 2], [3, 4]]) is None # (2,3) @ (2,2):维度不匹配
assert matmul([[10**6] * 200], [[10**6]] * 200) == [[2 * 10**14]] # 200 项累加到 2×10¹⁴,超过 32 位
assert matmul([[1, 2], [3, 4]], [[5, 6], [7, 8]]) == [[19, 22], [43, 50]] # 练习 1六条断言:四元素、两种特殊形状、维度不匹配返回 None、200 项 10⁶ 累加、练习 1 的 2×2。
展开完整参考程序 1:AI029 矩阵乘法与维度检查
完整程序:AI029(标准输入 → 标准输出)
Pythonimport sys
data = sys.stdin.read().split()
pos = 0
def take():
global pos
pos += 1
return int(data[pos - 1])
m, k = take(), take() # A 是 (m, k)
A = [[take() for _ in range(k)] for _ in range(m)]
p, n = take(), take() # B 是 (p, n)
B = [[take() for _ in range(n)] for _ in range(p)]
if k != p: # 先核对中间维度,再计算
print("shape mismatch")
else:
C = [[0] * n for _ in range(m)] # 结果 (m, n)
for i in range(m):
for j in range(n):
s = 0 # Python 整数不溢出;C++/Java 这里用 64 位
for t in range(k): # 公共维度 t:A 的第二个下标、B 的第一个下标
s += A[i][t] * B[t][j]
C[i][j] = s
print("\n".join(" ".join(map(str, row)) for row in C))读入顺序 m k / A / p n / B;k ≠ p 时只输出 shape mismatch。用两组样例和第 04 节的两种特殊形状核对。
展开完整参考程序 2:P2475 图像坏点矫正
完整程序:P2475(标准输入 → 标准输出)
Pythonimport sys
from math import floor
data = sys.stdin.read().split()
mat = [[int(data[3 * i + j]) for j in range(3)] for i in range(3)]
total = 0 # 周围 8 个元素之和
for i in range(3):
for j in range(3):
if (i, j) != (1, 1):
total += mat[i][j]
around = total / 8 # 周围均值
diff = abs(mat[1][1] - around)
if diff > 50:
mat[1][1] = floor(around + 0.5) # 四舍五入:加 0.5 向下取整,不用 round()
elif 30 <= diff <= 50:
mat[1][1] = floor((total + mat[1][1]) / 9 + 0.5) # 9 个元素的整体均值
for row in mat:
print(" ".join(map(str, row)))用题面示例(中心 200 → 10)和第 07 节的四组输入核对;思路与题目页参考题解相同。
09 / 边界、反例与复杂度
错误做法在具体输入上各输出什么
下面每一行都是一个具体的错误程序,给出输入、错误输出与正确输出;把参考程序改成对应写法就能复现。
| 错误做法 | 输入 | 错误输出 | 正确输出 | 判题结果 |
|---|---|---|---|---|
AI029 内层写成 B[j][t](把 B 当 Bᵀ) | 2×2:[[1,2],[3,4]] @ [[5,6],[7,8]] | 17 23 / 39 53 | 19 22 / 43 50 | 答案错误(WA) |
AI029 内层写成 A[t][i] | 第 04 节 (2,3)@(3,2) | 抛出 IndexError | 58 64 / 139 154 | 运行错误(RE) |
| AI029 不做维度检查直接相乘 | (2,3) @ (2,2) | 抛出 IndexError | shape mismatch | 运行错误(RE) |
| AI029 用 32 位整数累加(C++/Java) | 全 10⁶ 的 2×2 | 溢出成负数或错值 | 2000000000000 … | 答案错误(WA) |
P2475 用 round() | 中心 100,周围七个 10 一个 14 | 中心 10 | 中心 11 | 答案错误(WA) |
P2475 周围均值用整数除法 total // 8 | 同上 | 中心 10 | 中心 11 | 答案错误(WA) |
| P2475 中间段也用周围均值 | 中心 50,周围全 10 | 中心 10 | 中心 14 | 答案错误(WA) |
P2475 中间段写成 30 < diff | 中心 40,周围全 10(diff 恰好 30) | 中心 40(不变) | 中心 13 | 答案错误(WA) |
第一行的错误在方阵上不报错,只能靠手算表发现;第五、六行都在均值恰好 .5 时出错——round(10.5) 取偶数得 10,整数除法直接丢掉 .5。
| 做法 | 时间 | 本课规模下 |
|---|---|---|
| 三重循环 | O(m·k·n) | 200³ = 8×10⁶ 次乘加,Python 约 1–2 秒内 |
| P2475 固定 3×3 | O(1) | 瞬间完成 |
10 / 渐进练习与参考答案
跟做 → 改一个条件 → 独立实现 → 迁移
每题先在纸上或文件里做完,再展开答案。
练习 1(跟做):按第 04 节表的格式,算出 [[1,2],[3,4]] @ [[5,6],[7,8]] 的四个元素。
展开练习 1 答案
C[0][0] = 1×5 + 2×7 = 19;C[0][1] = 1×6 + 2×8 = 22;C[1][0] = 3×5 + 4×7 = 43;C[1][1] = 3×6 + 4×8 = 50。做错最常见的原因:B 取了行不是列(得 17、23、39、53)。
练习 2(改一个条件):题目改为给出 Bᵀ = [[5,7],[6,8]](即上题的 B 转置),要得到同样的 C,内层循环怎么写?
展开练习 2 答案
s += A[i][t] * Bt[j][t]——A 的第 i 行点乘 Bᵀ 的第 j 行;或先把 Bᵀ 转回 B 再用标准写法。直接把 Bᵀ 当 B 会得到 [[17,23],[39,53]]。
练习 3(改一个条件):P2475 的中间段改成「30 < diff < 50」,中心 40、周围全 10 的输出变成什么?中心 50、周围全 10 呢?
展开练习 3 答案
diff = 30 不再属于中间段、也不 > 50 → 中心保持 40;diff = 40 仍在中间段 → 14。区间端点归属只能按题面写,本题原文是 30 ≤ diff ≤ 50。
练习 4(独立实现):完成「代码自测」的 matmul,再加三条断言:维度不匹配返回 None;200 个 10⁶ 的行向量点乘同样的列向量 = 2×10¹⁴;练习 1 的 2×2。
展开练习 4 答案
matmul 的参考实现(自带断言)
Pythondef matmul(A, B):
m, k = len(A), len(A[0])
p, n = len(B), len(B[0])
if k != p: # 中间维度不相等:不能乘
return None
C = [[0] * n for _ in range(m)]
for i in range(m):
for j in range(n):
s = 0
for t in range(k): # A 的第二个下标、B 的第一个下标都是 t
s += A[i][t] * B[t][j]
C[i][j] = s
return C
A = [[1, 2, 3], [4, 5, 6]]
B = [[7, 8], [9, 10], [11, 12]]
assert matmul(A, B) == [[58, 64], [139, 154]] # 第 04 节四个元素
assert matmul([[1, 2, 3]], [[4], [5], [6]]) == [[32]] # 行向量 · 列向量 → 1×1
assert matmul([[2], [3]], [[4, 5]]) == [[8, 10], [12, 15]] # 外积 → 2×2
assert matmul(A, [[1, 2], [3, 4]]) is None # (2,3) @ (2,2):维度不匹配
assert matmul([[10**6] * 200], [[10**6]] * 200) == [[2 * 10**14]] # 200 项累加到 2×10¹⁴,超过 32 位
assert matmul([[1, 2], [3, 4]], [[5, 6], [7, 8]]) == [[19, 22], [43, 50]] # 练习 1见第 08 节展开区(同一份代码)。
练习 5(迁移):给 P2475 构造一组「周围均值恰好 .5」的输入,手算用 floor(x + 0.5) 和用 round(x) 各得多少;再构造一组 diff 恰好 50 的输入,说明它属于哪一段。
展开练习 5 答案
周围七个 10 一个 14、中心 100:周围均值 10.5,floor(11.0) = 11,round(10.5) = 10。diff 恰好 50:周围全 10、中心 60 → 属于 30..50 段,用整体均值 (60 + 80) / 9 = 15.56 → 16。
11 / 读题要求与复习自评
两道题的要求对照,以及完成本课之后怎么复习
提交前把下表过一遍;题目页的题面与样例是最终依据。
| 项目 | AI029 矩阵乘法与维度检查 | P2475 图像坏点矫正 |
|---|---|---|
| 输入 | m k、A 的 m 行、p n、B 的 p 行 | 3 行各 3 个整数 |
| 输出 | m 行每行 n 个整数;k ≠ p 时 shape mismatch | 矫正后的 3×3 |
| 关键检查 | 先核对维度;64 位累加 | 两个均值不混用;floor(x + 0.5);端点含等号 |
| 示例 | 样例 1 (2,3)@(3,2) → 58 64 / 139 154;样例 2 → shape mismatch | 10 10 10 / 10 200 10 / 10 10 10 → 中心 10 |
需要对照解法时,展开本页第 08 节的两份完整参考程序。复习与自评:本课的「学习完成检查」六条是自评,不改变题目的通过(AC)状态,本课算完成的条件以页面下方「学习完成检查」处的说明为准。复习时用三个问题自测:① 不看正文,写出三重循环并说出下标对位规则;② 不看表格,重算 (2,3)@(3,2) 的四个元素;③ 说出 P2475 三段各用哪个均值、.5 怎么取整。答不出哪一条,就回到对应的节重读,再做第 10 节对应的练习。
12 / 练习
按顺序完成本课的任务
必做题已通过 0/2 道
编写矩阵乘法函数(matmul):断言全部通过后再提交
代码自测自主练习练习重点:三重循环与维度校验;用手动推演的四个元素和两种特殊形状做断言;预计用时:20 分钟
完成标准:能不看模板写出下标全部正确的三重循环,三条断言全部通过
需要时查看提示
最内层是 C[i][j] += A[i][t] * B[t][j],t 走 0..k-1。断言里的 [[32]] 是 1×3 行向量点乘 3×1 列向量。参考实现在第 08 节展开区。
自测代码(复制到你的代码文件中运行,检查输出是否一致)
A = [[1, 2, 3], [4, 5, 6]]
B = [[7, 8], [9, 10], [11, 12]]
# 正文示例中四个矩阵元素的计算结果
assert matmul(A, B) == [[58, 64], [139, 154]]
# 特殊形状:行向量 × 列向量 → 1×1;k=1 时的外积 → m×n
assert matmul([[1, 2, 3]], [[4], [5], [6]]) == [[32]]
assert matmul([[2], [3]], [[4, 5]]) == [[8, 10], [12, 15]]AI029 · 矩阵乘法与维度检查
必做任务 1练习重点:先做维度检查;k ≠ p 时输出 shape mismatch;乘加用 64 位整数;预计用时:30 分钟
完成标准:能说出为什么这题必须用 64 位整数做累加
需要时查看提示
维度检查必须在计算前完成;shape mismatch 是唯一合法的错误输出,需逐字符一致。输出每行 n 个整数、单个空格分隔;Java 用 StringBuilder 汇总后一次输出。输入顺序是 m k、A、p n、B。第 04、06 节有逐项表与数值表。
P2475 · 图像坏点矫正
必做任务 2练习重点:3×3 邻域均值、diff 三段规则、四舍五入取整;预计用时:25 分钟
完成标准:能说清三段规则各用哪个均值、取整用什么规则
需要时查看提示
中心是位置 (1,1)(下标从 0 开始)。diff > 50 用周围 8 个的均值,30 ≤ diff ≤ 50 用全部 9 个的均值,diff < 30 不动——两个均值不要混用。「四舍五入取整」用 floor(x + 0.5),不要直接依赖语言默认的取整函数(round),下一课「浮点精度与稳定 softmax」会详细讲。第 07 节有逐例表。
提交结果
提交结果说明与处理方法
- WA
答案错误
三个常见错误:内层下标没对齐 t、把转置当原矩阵、P2475 的两个均值混用或 .5 取整错;先用手动推演的四个元素逐项核对。第 09 节的表给出了每种错误的具体输出
- PE
格式错误
AI029 每行 n 个整数单空格分隔、行尾无多余空格;
shape mismatch需逐字符一致- RE
运行错误
多半是没校验维度就开始相乘,下标越界;先判断 k == p 再进循环
- TLE
超时
200³ = 8×10⁶ 次乘加在时限内够用;超时先查 Java/JS 是否在循环里拼字符串
- CE
编译错误
C++/Java 声明累加变量时就用 64 位类型,不要算完再转换
- AC
通过
记下这套核对流程:先用小例子跑断言,再提交——模块 6 与模块 7 的每道数值题都这样做
13 / 学习完成检查
本课学习完成检查
完成本课需要:必做题全部通过,并勾选本课的全部学习完成检查;进阶练习、基础加练与复习题单独统计,不影响完成状态。登录后,勾选记录会保存到账号,并更新课程总览的完成状态。