CSP 复赛专题 2 · 枚举椰程信奥 · 互动课件
10:00
1 / 19
🇨🇳 国庆集训 · Day 2

枚举

把所有可能的答案「一一列举」出来再加以判断——这就是枚举,也是暴力枚举、穷举。
今天带着两步走:先把答案的空间想清楚,再把空间的边界砍下来。
枚举四步法 四大常见题型 两道真题:数字盒子 · 传送带 椰程信奥当堂测评
开场 2 分钟:先问「你上次比赛 T1 是怎么过的?」再点明今天的目标—— 枚举不是「笨办法」,而是比赛里性价比最高的保底分手段。国庆集训期间请同步把两题挂到椰程信奥上,讲完即测。
学习目标

今天下课时,你必须能自己说出这三句话

① 说得出「枚举什么」

看到一道题,先找出枚举的要素:枚举谁?枚举几层?可能情况一共有多少种?

② 砍得动「枚举空间」

枚举范围定在哪里?哪些情况根本不必枚举?把 10⁹ 砍到 10⁶ 才是真本事。

③ 写得出「枚举代码」

循环嵌套顺序、边界取模、判环标记——三道容易踩空的坑,今天一次填平。

🔥 课前热身:先凭直觉答,不要想太久

下列哪一句最接近「枚举」的本质?

限时 90 秒抢答。第二、三项选项要当场追问「为什么不是」: 猜测没有穷尽性、不能证明最优;只走一条路那是贪心/最短路,不是枚举。点出「穷尽 + 判断」这两个词。
环节一

枚举是什么:定义 + 四步法

枚举 = 把「所有可能」一个一个试,留下符合条件的所有可能符合?✓✗ 扔掉关键不是「会不会试」,而是「能不能少试一点」——所以才有建模型、砍空间。

📖 定义

枚举就是把所有可能的答案一一列举出来,再加以判断, 又称暴力枚举、穷举。

判据只有两条:穷尽(不重不漏)+判断(每个候选都能验真伪)。

🧭 做题四步法

1 建模型枚举哪些要素?各有多少种?—— 必须说出一个数,比如 8N³。
2 砍空间哪些情况根本不必枚举?提前排除掉。
3 定顺序从前往后枚举,还是从后往前枚举?
4 会判断写完不算完:结果对不对?写法对不对?

前 3 步来自原课例的「三步骤」,第 4 步是本课补上的 工程落地一步——今天有一道真题会专门讲它。

🎯 小练:把四步法按正确顺序点出来(点四次)

四步里第 1 步的「说出一个数」与第 2 步才是分水岭:学生普遍只会"硬枚"和"换个顺序试试", 结果复杂度下不来。第 1 步强制报出规模(防止敢乱枚),第 2 步才谈得上砍(防止枚不动)。 数字盒子靠数据范围告诉你 8N³ 很小、放心枚;传送带靠「同一个格子第二次到达已经没有新信息」砍掉重复模拟。 第 4 步「会判断」在真题一的代码走读页兑现——那里有一个真实的"AC 了但写法不对"案例。
3D🎲 枚举 = 走遍整个立体解空间🖱 拖拽旋转 · 双击复位
为什么用 3D:枚举的关键是不重不漏。把解空间画成 3×3×3 的立体点阵,学生能亲眼看到「扫完一层再扫下一层」的顺序——这正是 for 循环嵌套的物理意义。
环节二

枚举算法常见题型:四大类 · 八小类

四类枚举题:先认出是哪一类,再决定砍空间的手法① 枚举数在一段范围里试例:试每一个 x② 枚举位置在二维/序列里试例:试每个格子③ 枚举排列全排列 / 组合例:n 个数排一排④ 枚举方向8 方向数组例:上下左右+斜砍空间的三把刀:① 缩小上下界(用数学算边界)② 跳过不可能(剪枝 / 提前 break)③ 换枚举对象(枚举「答案」而不是枚举「方案」)

点开每张卡片,看它「枚举什么、怎么砍空间」。

🔢 基础枚举

数值枚举
遍历区间 [1, n],筛选满足条件的数

例:被 3 整除且各位和为偶数

🔤 基础枚举

字符串枚举
遍历字符/字符串集合,匹配特定模式

例:以指定字母开头且长度为偶数

🧩 组合枚举

子集枚举
位运算 / 递归枚举子集再筛选

例:元素和能被 k 整除

🧩 组合枚举

排列枚举
回溯生成全排列再筛选

例:无重复数字且能被指定数整除

⚙️ 算法结合

枚举 + 贪心
枚举关键状态后应用贪心策略

例:任务分配顺序枚举 + 贪心分配资源

⚙️ 算法结合

枚举 + 动态规划
枚举状态后用 DP 解子问题

例:背包容量枚举 + DP 求最优解

🏕️ 场景枚举

生活场景
枚举活动组合,求最大兼容活动数

例:时间安排问题

🎮 场景枚举

游戏场景
枚举移动方向,搜索迷宫路径

例:BFS/DFS 遍历方向

这张表不要逐条念。做法:先让学生自己归类,再点开卡片校对。 重点提醒:今天两道真题都属于「基础枚举」——数值/网格枚举,是全套题型的地基; 子集与排列枚举留给 Day 3 的回溯专题。
每日一题 · 真题一

[ABC258B] 数字盒子 Number Box

📄 题意

有一个 N × N 的数字方格网,上下边缘相连、左右边缘相连。

先在 8 个方向(上下左右 + 四斜向)中选一个,再从任意格出发移动一格, 重复 N − 1 次,共经过 N 格。

把经过的格子上的数字按顺序拼成一个整数,求最大值。

数据范围:1 ≤ N ≤ 10,1 ≤ A[i][j] ≤ 9。

🔍 先找枚举要素

枚举谁① 起点 ② 方向
有多少起点 N² 个,方向 8 个 → 共 8N² ≤ 800 种
怎么判断每种情况拼出一个整数,一路取 max
复杂吗O(8N³),N ≤ 10 时不到 1 万次操作
两要素、两层循环、一个取 max —— 这就是「建模型」。

💡 样例

输入

4
1161
1119
7111
1811

输出

9786

下一屏我们把「为什么是 9786」算给你看。

读题时间 2 分钟,先让学生自己说「枚举要素是什么」。 关键追问:「为什么起点是 N² 而不是 1 个?」「为什么方向是 8 个而不是 4 个?」 确认人人能说出「上下相连、左右相连」意味着越界要绕回去,这是后面代码的伏笔。
每日一题 · 真题一

为什么是 9786:把网格「铺开」看环绕

因为网格上下左右都是循环的,所以我们把 4 组数据粘起来,模拟出循环的样子。

正式网格(4×4,点击任意数字设为起点)

起点(第 2 行 第 4 列)→ 朝右下:9

铺开后的 8×8:把 4×4 横竖各接一份自己

已走过  当前格 | 粗线=两组数据的接缝
固定演示:起点第 2 行第 4 列、方向右下 —— 点「走一步」开始
—

🧮 手动走一遍:同一条路线,两种画法

在 4×4 环上看(会绕回)
(2,4) → (3,1) → (4,2) → (1,3)
数字依次 9、7、8、6
在铺开的 8×8 上看(一条直线)
(2,4) → (3,5) → (4,6) → (5,7)
数字依次 9、7、8、6 → 拼成 9786

两条路线取到的数字完全一样——这就是「环绕」的本质: 走出去的格子,其实就是对面那一格的另一份拷贝。铺开只是把我们心里绕的那一下,画成了直线。

这一页是全班最难的一步:学生算不对 9786,往往不是不会拼数,而是没意识到越界后要「绕回对面」。 做法:先请一位同学上台在右侧铺开图上用手指走一遍(点「走一步」逐步揭示),走错就停在那一步追问「下面那一格是谁?」 走通之后再回到左侧正式网格,指认同一条路线。务必点明「右图是直线、左图是绕圈,但取到的数字相同」。
每日一题 · 真题一

动手枚举:换方向,答案就变了

点数字改起点,点下面的米字格按钮换方向。

当前枚举

🎯 体会「枚举空间」

起点 4² = 16 个 × 方向 8 个 = 128 种情况,每种拼一个 4 位整数,取最大。

如果这道题是 N = 2000 呢?8N³ 早就爆了——那时就得靠「砍空间」,而这题的数据范围告诉你:放心枚。

🏁 全班挑战

把方向全部试一遍,说出最大整数是多少?它是哪个起点、哪个方向走出来的?(答案在下一屏)

请 3~4 名学生轮流上台点方向,其余同学在草稿纸上记录「起点 + 方向 + 拼出的数」。 务必让全班亲眼看到:有些方向拼出来是 1161、有些是 9711,最大值只出现在「右下」。 这就是「枚举 = 全部试一遍再取最优」的具身经验。
每日一题 · 真题一

方向数组(上):八个方向怎么记、怎么定义

八个方向写 8 段 if-else 也能过,但循环不起来。方向数组让「试遍所有方向」变成一行 for。

① 怎么记:米字格 + 相对坐标变化

红格是当前所在格 (x, y),要从它走到周围 8 格, 需要的就是每一格相对它的坐标变化量 (dx, dy)。点右边表格的任意一行,这里会亮起对应那一格。

② 定义:两个「平行数组」

// 下标 k 是同一层的意思,两个数组相同 k 取出的就是一对
int dx[8] = {-1,-1,-1, 0, 1, 1, 1, 0};
int dy[8] = {-1, 0, 1, 1, 1, 0,-1,-1};
kdx[k]dy[k]方向行列怎么变
0-1-1左上行 −1、列 −1
1-10上行 −1
2-11右上行 −1、列 +1
301右列 +1
411右下行 +1、列 +1
510下行 +1
61-1左下行 +1、列 −1
70-1左列 −1

顺序是「从左上开始顺时针」。因为 8 个方向最终都要走到, 顺序不影响答案——但固定一个顺序,调试和讲课都好对照。

这一页是从「会点按钮」到「会写代码」的桥,约 3 分钟。 只做两件事:① 让学生对着米字格把 8 组 (dx, dy) 逐个念出来,念错「dx 管行、dy 管列」立刻纠正; ② 追问「为什么没有 (0,0)」——原地不动会让判环误判,不判环就是死循环。
点完米字格就翻下一页,四条知识点和两个翻车点留到下一页再给。
每日一题 · 真题一

方向数组(下):怎么用、要小心什么

三个动作 + 两种边界,再加六条动手前必扫的知识点。

③ 怎么用:把「试遍所有方向」拆成三个动作

动作 1 · 算出下一格
int nx = x + dx[k];
int ny = y + dy[k];
先只算,不动 x、y
动作 2 · 判断边界
有墙/会走出去 → continue 跳过这个方向
环形相连(本题)→ 用取模绕回去
动作 3 · 安全才前进
x = (x + dx[k] + n) % n;
y = (y + dy[k] + n) % n;
先算再判后赋值,下标永不越界
// 4 方向版本:把 8 换成 4,循环体一个字都不用改
int dx[4] = {-1, 0, 1, 0};
int dy[4] = { 0, 1, 0,-1};

for (int k = 0; k < 4; k++) {
  int nx = x + dx[k], ny = y + dy[k];
  if (nx < 0 || nx >= n || ny < 0 || ny >= n)
    continue;            // 出界,跳过这个方向
  // …在这里处理 (nx, ny)…
}
「有墙」和「环绕」是两种完全不同的边界
· 题面说「越界就不合法」→ 用 continue 跳过;
· 题面说「上下相连、左右相连」(本题)→ 用 (… + n) % n 绕回去。
走错门就会「样例过、提交挂」。

④ 相关知识点(六条,动手前扫一眼)

知识点要点
为什么要用数组 把「变化规律」放进表里,循环体只写一遍。for (k = 0; k < 8; k++) 就等价于 「所有方向各试一次」,不用写 8 段搬来搬去的 if-else。
dx 管行,dy 管列 最容易写反的一处:dx 是行(上下)的变化,dy 是列(左右)的变化。 写反了程序照样跑、不报错,但方向全错——典型的「编译通过、答案全错」。
数组长度必须等于方向数 循环写 k < 8 而数组只开了 4 个元素 → 越界读,拿到的是内存里的随机值。 本地小数据可能侥幸过,交到 OJ 上就是 WA 或 Runtime Error。
中心 (0,0) 绝不能写进去 加上它就等于「原地不动」:判环会误判,不判环则直接死循环。
同一套外壳能换「步法」 国际象棋「马走日」:dx[8]={1,1,-1,-1,2,2,-2,-2}、 dy[8]={2,-2,2,-2,1,-1,1,-1};三维网格加一个 dz; 六边形网格是 6 个方向。方向数组是「枚举移动」的通用外壳。
起点和方向是两个维度 本题在方向数组外面还套了一层「起点」循环:外层遍历 8 个方向、内层遍历每个格点 (i,j) 作为起点。 方向和起点是互相独立的两个枚举要素,所以总情况数是 N² × 8,而不是 N² + 8。
⚠️ 两个高频翻车点
① dx/dy 抄错一位 → 8 个方向里有一个是错的,本地样例可能照样过。 动手前先把 8 个方向在纸上逐个口述一遍。
② 取模忘写 + n → C++ 里负数取模仍是负数,下标越界。写取模时顺手把 + n 打上, 再用一组「起点在最左边、方向朝左」的数据自测一次。
约 3 分钟。六条知识点不要逐条讲,只挑「dx 管行 dy 管列」「数组长度必须等于方向数」两条强调, 其余留给学生自己扫。「起点也是枚举要素」这条必须点明——它是本题 N² × 8 的来源,也是下一页三层循环的伏笔。
最后用一个问题过渡到下一页代码:「如果题目没说上下相连,该用 continue 还是取模?」
每日一题 · 真题一

代码走读:三处关键,一处易错

// 8 个方向的相对坐标变化数组
int dx[8] = {-1,-1,-1, 0, 1, 1, 1, 0};
int dy[8] = {-1, 0, 1, 1, 1, 0,-1,-1};

for (int i = 0; i < n; i++)
  for (int j = 0; j < n; j++)
    for (int k = 0; k < 8; k++) {
      int x = i, y = j;   // ① 起点每个方向都要重置
      long long num = 0; // ② 必须 64 位
      for (int c = 0; c < n; c++) {
        num = num * 10 + (g[x][y] - '0');
        x = (x + dx[k] + n) % n;  // ③ 加 n 防负数
        y = (y + dy[k] + n) % n;
      }
      ans = max(ans, num);
    }

🔑 三层循环各管什么

最外层起点行 i
中间层起点列 j
内层方向 k —— 方向不同,后续整条路线都不同
⚠️ 最隐蔽的坑:起点重置写在哪?
视频里把 int x = i, y = j; 写在了方向循环外面。它在本题(环形网格)里其实恒正确—— 因为在环形网格上平移是一一对应的——每个格子恰好被走到一次,既不重复也不漏。 无论 N 是几、无论走几步,起点虽没重置,绕完 8 个方向仍覆盖全部 N²×8 种组合,一个不漏。
但它只在"网格首尾相连"时成立:普通(有墙)网格里起点会随方向漂移,大量组合被跳过而直接出错(实测 3 万组随机数据 22068 组不一致)。 所以工程上一律写在方向循环内部——这不是"视频侥幸",而是"你写的下一题多半不是环形"。结果正确 ≠ 写法可迁移。

✍️ 三连问

① ans 和 num 如果声明成 int,会发生什么?

② 取模写成 x = (x + dx[k]) % n 会怎样?

代码不要照抄。做法:投影出上面这段,逐个高亮 ①②③ 三处, 每次先问「这行删掉会怎样」再公布答案。关于起点重置一定要讲清: 别让学生的正确代码因为「和视频不一样」而自我怀疑,也别让他们把"只在环形网格才成立的写法"当成万能模板照搬。
课后挑战 · 真题二

[ABC265C] 传送带 Belt Conveyor

📄 题意

H 行 W 列网格,每格写着 U D L R 之一,表示站在该格时往哪个方向移动一格。

从 (1,1) 出发,不断重复操作,直到无法再移动为止:

  • G[i][j] 是 U 且 i ≠ 1 → 移到 (i-1,j)
  • G[i][j] 是 D 且 i ≠ H → 移到 (i+1,j)
  • G[i][j] 是 L 且 j ≠ 1 → 移到 (i,j-1)
  • G[i][j] 是 R 且 j ≠ W → 移到 (i,j+1)
  • 都不满足 → 停住

输出停住时所在的格子;若永远走不停,输出 -1。

🔍 先找枚举要素

枚举谁不用枚举!路线由格子字符唯一确定
循环什么一直循环「读字符 → 走一步」
怎么判断走到重复格子 = 死循环;走出网格 = 停住
复杂吗最多经过 H × W ≤ 250000 格,循环模拟即可
别用 BFS!这题不是「找一条最短路」,而是「照着格子走」。

💡 样例 1 / 样例 2

样例 1(输出 1 3)

2 3
RDU
LRU

样例 2(输出 -1)

2 3
RRD
ULL

下一页的模拟器里还准备了两组课堂加练样例(4×4 走 11 格停住、5×5 走 15 格后死循环),可以现场切着走。

先不给解法。让学生自己在草稿纸上把样例 1 的路线写出来—— 会发现它「绕了一圈又一圈但还是停下来了」;再做样例 2,发现它「真的转不完」。 认知冲突建立后再问:你怎么知道它转不完?由此自然引出标记数组。
课后挑战 · 真题二

亲手走一遍:停住还是转圈?

选择样例 → 点「走一步」或「自动走」 → 观察什么时候必须停下来。

样例
播放
速度
等待开始:站在 (1,1)
已走步数:0  格子总数 H × W:6
输出:—
路径记录:
(1,1)

🧠 判环的三条线索

① 用 vis[i][j] 记录到过的格子;

② 又踩到 已经访问过 的格子 → 说明成了一个环,永远出不来 → 输出 -1;

③ 下一步会走出网格 → 立刻停在当前格并输出坐标。

补充:也可以用「步数超过 H×W 就判环」的写法,等价但不如标记数组直观。

⚠️ 输出的是哪一格?

输出的是停在的那一格,也就是「移动前」的格子,不是越界后想象中的那一格。

样例 1 的终点是 (1,3) —— 你如果输出了 (1,4),就是这一类错误。

自动走的时候把速度调慢(本页每步 380ms),让学生跟着数格子。 切到样例 2 后会看到它转回 (1,1) 那一刻——这就是判环的瞬间, 一定要在这里按暂停并追问「你凭什么说它永远停不下来?」引导学生说出「因为它会一模一样地再来一遍」。
课后挑战 · 真题二

代码走读:一个 while,三个出口

int x = 1, y = 1;
while (true) {
  if (vis[x][y]) { // 出口 1:判环
    cout << -1; return 0;
  }
  vis[x][y] = true;

  int nx = x, ny = y;
  char c = g[x][y];
  if (c == 'U') nx--;
  else if (c == 'D') nx++;
  else if (c == 'L') ny--;
  else ny++;            // 'R'

  if (nx < 1 || nx > h ||
      ny < 1 || ny > w) {  // 出口 2:出界
    cout << x << " " << y;
    return 0;
  }
  x = nx, y = ny;           // 出口 3:继续走
}

🔑 三处判断的顺序很重要

先判环当前格是否来过
再算下一步用 nx, ny 试探,不动真格
后判出界越界就立刻输出当前格
「先算后判、不越界才前进」是模拟题的通用护身符。
⚠️ 常见的两个错
① 把 if (vis[nx][ny]) 写在出界判断之前:网格外那一圈的下标也落在数组里, vis 一旦开小就是 RE。
② 输出成「移动后的坐标」:样例 1 会变成 (1,4),白丢分。

✍️ 两连问

① 这题为什么不能用 BFS 求最短路?

② 从 (1,1) 出发,最多可能走多少步?

这两问直指复赛丢分点:模型选错(拿 BFS 硬套)与不判终止(死循环 TLE)。 讲完立刻上椰程信奥提交,让对错在评测机上说。第 ② 问可延伸到时间估算:25 万步 × 每步常数 ≈ 毫秒级。
易错辨析

四句话,先投票,再讲理

凭直觉点「对」或「错」,再点「看解析」。

① 枚举就是最笨的暴力,纯粹浪费时间,能不用就不用。

❌ 错。枚举是比赛里性价比最高的保底手段:先拿稳分,再想优化。 复赛 T1/T2 有相当比例就是纯枚举或枚举加小技巧;「先枚后优」也是主流解题路径。

② 数字盒子里,方向循环内部的起点 x,y 必须重新赋值。

✅ 对。规范写法里每个方向都要从同一个起点重新出发。视频的写法在环形网格上确实也全对(环面平移一一对应、不重不漏,与步数、N 是否互质无关);但普通(有墙)网格会漏掉大量组合。所以工程上统一写在循环内部最稳。

③ 传送带中,走到已访问过的格子就说明进入了死循环。

✅ 对。路线完全确定、状态只有「在哪一格」这一个,所以重复出现某一个格子,就必然无限重复,输出 -1。

④ 传送带里,先判 vis[nx][ny] 再判出界,反正数组开大点就行。

❌ 错。这是把正确性寄托在数组开多大上。规范做法是先判出界再访问数组;否则一旦数据范围变大、数组开小,就直接 RE。
先全班举手表决,记录票数,再揭晓答案——让错误的前概念先暴露出来。 第 ② 条最容易出现「少数派」,请持正确观点的学生来解释,教师只做补充。 第 ① 条如果全班都觉得「枚举低级」,要用「先拿分再优化」的赛事实例纠正。
小结

枚举知识树:一棵主干,四条分支

枚举 穷尽 + 判断 ① 建模型 枚举谁?情况有多少? ② 砍空间 范围?哪些不必枚? ③ 定顺序 前往后 / 后往前? ④ 会判断 拼数 / 取模 / 判环 · 起点 × 方向 = 两层枚举(数字盒子) · 环形偏移 (x+dx+n)%n,防负数 · 拼数用 long long,答案可能超 int · 传送带:不枚举,照格模拟 · vis 标记判环,先判出界再访问数组

🏁 今天带走一句话

先把答案空间想清楚,再把空间的边界砍下来;能枚就枚,枚完再想优化。

小结务必让学生口头补全,不要教师照读。可以遮住右侧叶子条,让学生自己说出 5 条要点; 说不出的当场翻回对应页。最后一句「能枚就枚」是本专题的价值观,要念得慢、念得重。
拿分

一道题 100 分是分档给的——不会正解也要先拿保底

复赛一道题的 100 分由十几到二十几个测试点组成, 前面几档专门为「没想出正解的人」准备。四道题各拿 30~40 分, 加起来往往就是一等奖和二等奖的分界。

第 1 档 特判 5~10 分 约 2 分钟 第 2 档 暴力 20~30 分 约 8 分钟 第 3 档 特殊性质 40~60 分 约 15 分钟 第 4 档 正解 100 分 约 25 分钟

① 特判档:先别想算法,看数据范围表

题目给的数据范围表就是出题人给你的送分清单。看到「n = 1」「只有一组数据」这类一行, 就先写个 if 直接输出答案。2 分钟换 5~10 分,全场最划算。

② 暴力档:按题意最直白地写一遍

多重循环、DFS 全枚举、朴素 O(n³)……不要优化,只要保证最小那档全对。 它既是保底分,又是后面对拍的标尺——没有它你无法证明正解是对的。

③ 特殊性质档:题目里那句「若……」

常见的送分性质:数据已经有序、所有值完全相同、规模小到可以 O(n²)、 只出现一种类型。题目写出来就是让你拿的,专门写一份即可。

④ 正解档:思路定了,就赢了八成

考场上的时间几乎都花在想思路上,不是写代码。写完先跑样例, 再用第 ② 档的暴力版造小数据对拍——这是唯一能证明你思路对的办法。

考场纪律:每档设时间上限,到点还没调通就 立刻提交当前版本,保住已有分数,再往上冲。最常见的翻车是"正解写了 50 分钟没过,连暴力分都没交上去"。
拿分

本讲 2 道题,各自的四档怎么走

数字盒子 / Number Box · ENUM258B

第1档 · 2 分钟
N == 1 时只有一个格子,答案 1 或 0;格子字符全同时先手算一遍

第2档 · 8 分钟
每格 × 8 个方向 × N 个字符逐字比,O(8N³),N ≤ 10 完全跑得完

第3档 · 10 分钟
先只做 4 个正方向(下/右/上/左),拿到一半分再补 4 个斜向

第4档 · 15 分钟
8 个方向数组 + 下标取模,把环面当普通数组走

传送带 / Belt Conveyor · ENUM265C

第1档 · 2 分钟
起点就是终点 → 输出 0;棋盘上没有箭头格 → 退化成普通网格 BFS

第2档 · 8 分钟
直接 BFS,把「滑行」当成一步一步走,N ≤ 20 稳过

第3档 · 10 分钟
预处理每个箭头格「最终滑到哪一格」,把整段滑行压成一条边

第4档 · 15 分钟
0-1 BFS:滑行边权 0、步行边权 1,用 deque

50 分钟时间盒(一题的节奏):
0–5 分钟 读题 + 圈出数据范围表里最小的那几档 → 5–15 分钟 写完第 1、2 档并先交一次(保住 20~30 分)→ 15–40 分钟 冲第 3、4 档 → 40–50 分钟 造小数据对拍、检查 freopen 与文件名。
课堂上别让学生"从头想正解"。先要求每个人 15 分钟内交出第 1、2 档, 再放开冲正解。这个顺序一换,平均分通常能涨一大截——因为它杜绝了"想了 40 分钟,交上去 0 分"。
当堂检测

三道小题 + 两道真题提交

🧪 速答三题

① 工程上为什么要求把起点写在方向循环内部?

② 传送带输出的是哪一格?

③ 传送带判环,最直观的做法是?

💻 上机任务(椰程信奥 OJ)

必做ENUM258B 数字盒子 —— 目标:AC 12 / 12
必做ENUM265C 传送带 —— 目标:AC 13 / 13
进阶把数字盒子的移动步数改成 K 步(K 由输入给定),还能过吗?
两题都在国庆集训题单里,讲完即测,当场看榜。

📌 提交前自查四件事

① 答案变量是否 64 位? ② 取模有没有加 n?

③ 起点是否写在方向循环内部? ④ 判环 / 出界的顺序对不对?

速答三题 3 分钟,全部答对再上机。务必留出至少 25 分钟上机时间, 巡视重点关注「样例过、隐藏点 WA」的学生——他们踩的正是今天讲过的坑,当场对号入座,印象最深。
拓展附录

知识补给站:课前该会、课后能拓

前面两道真题默认你会了一些"基本功",也埋了几个能往深处走的口子。这里一次补齐。

🧰 前置补给(默认你会、但课上没讲)

① 字符网格读入:先读行 cin>>s 或 getline,再逐字符 s[j]-'0' 转数字。

② c-'0' 才是数字:char 直接当 int 拿到的是 ASCII('0'=48),必须减 '0'。

③ 0-based / 1-based 别套错:258B 用 0-based 坐标,265C 用 1-based(vis[505][505] 的 505 是 1-based 余量)。跨题照搬必 WA。

④ 静态数组尺寸:int a[505][505] 开在栈上,太大(≈1e6 个 int 量级)会栈溢出;要么缩小,要么开全局 / vector。

⑤ 整型临界:int 上限 2147483647(10 位)。N=10 拼 10 位数→必用 long long;N≥19 连 long long 都超(需 __int128 / 字符串)。

⑥ printf 格式:printf("%d", (long long)x) 是未定义行为,必须 %lld。

⑦ vis / ans 初值:每个测试点 memset(vis,0) 清零;求最大别把 ans 初始化成 0(可能全负)。

🚀 横向扩展(把枚举从"会做"升到"看得透")

① 判环不止 vis:Floyd 快慢指针(龟兔赛跑)边走边判,免 vis 数组、额外 O(1) 空间。

② 抽屉原理证步数上限:传送带每格唯一方向,H×W 步内必重复或到达——走超 H×W 步还没到就直接判 -1,不用 vis 也能定上界。

③ 乘法原理升维:本题 N²(起点)×8(方向)= N²×8,是"独立要素相乘"而非相加;多个独立枚举要素都这么算。

④ 二分 / 折半枚举:答案单调时,枚一半、算另一半,把 O(N²) 降到 O(N log N)。

⑤ 大数延伸:N≥19 拼数超 long long → 上字符串 / 高精度,或只比位数与字典序。

⑥ 环面一一对应(回扣本课):起点写循环外在环形网格恒对,正是因为"平移一一对应、每个格子恰好走到一次"——这页前半的坑,根上都在这。

📌 怎么用这页
课前用「前置补给」自查:哪条你其实不会,先补再上机。课后用「横向扩展」挑 1—2 条当微专题,下次课用 8 分钟串讲,枚举专题就真正"成体系"了。
这页是补给站不是必讲页:国庆集训时间紧就只投「前置补给」拦一遍,避免学生卡在语法而非算法;横向扩展留作学有余力者的选做清单。

课件目录