第 4 章 枚举、前缀和、差分与双指针
本章目标:学习如何把朴素枚举优化成可通过的数据规模,掌握线性扫描中的常见加速技巧。
4.1 学习目标
- 理解枚举的维度和复杂度来源。
- 掌握一维、二维前缀和。
- 掌握一维、二维差分。
- 掌握双指针和滑动窗口。
- 能判断一个窗口问题是否具有单调性。
4.2 枚举不是坏事
很多算法从枚举开始。关键是枚举什么。
例如三数之和朴素枚举:
排序后固定一个数,再用双指针找另外两个数:
优化的本质是减少枚举维度,或让每个维度移动次数变少。
4.3 前缀和
一维前缀和定义:
区间 的和:
使用 0-index 时常写成:
区间 的和:
4.3.1 为什么建议左闭右开
左闭右开 有三个好处:
- 长度等于 。
- 空区间可表示为 。
- 和数组切片习惯一致。
4.4 二维前缀和
对矩阵 ,定义:
递推:
矩形 到 的和:
关键是减掉多加的左上角。
4.5 差分
如果前缀和适合“多次查询区间和”,差分适合“多次区间修改”。
一维差分:
对区间 加 x:
最后做一次前缀和还原数组。
4.6 二维差分
对矩形 到 加 v:
最后做二维前缀和还原。
4.7 双指针
双指针通常分为两类:
- 相向双指针:左右往中间走。
- 同向双指针:维护一个窗口。
4.7.1 相向双指针
有序数组两数和:
int l = 0, r = n - 1;while (l < r) { int sum = a[l] + a[r]; if (sum == target) return true; if (sum < target) l++; else r--;}正确性来自有序性:sum 小时只能增大左端,sum 大时只能减小右端。
4.7.2 滑动窗口
当右端增加使条件单调变坏,左端增加使条件单调变好,就可以滑窗。
例:最短子数组和至少为 target。
int l = 0;long long sum = 0;for (int r = 0; r < n; r++) { sum += a[r]; while (sum >= target) { ans = min(ans, r - l + 1); sum -= a[l++]; }}如果数组有负数,上述单调性不成立,需要换思路。
4.8 离散化
当坐标很大但点数很少,可以离散化。
流程:
- 收集所有会用到的坐标。
- 排序去重。
- 用下标代替原坐标。
离散化保留的是相对顺序,不保留原始距离。若题目需要区间长度,还要保留相邻坐标差。
4.9 易错点
- 前缀和数组长度少开 1。
- 混用闭区间和左闭右开。
- 二维前缀和忘记减左上角。
- 差分忘记处理 r+1 越界。
- 有负数时错误使用滑动窗口。
- 离散化后忘记处理重复坐标。
4.10 练习
- 用前缀和回答多次区间和查询。
- 用二维前缀和求矩形区域和。
- 用差分处理多次区间加法。
- 用双指针解决三数之和。
- 判断一个窗口问题是否能使用滑动窗口,并说明原因。
ACM/OI 扩展:扫描线、莫队与离线技巧
本节补充 OIer 和 ACMer 常用的算法套路、模板、复杂度分析和易错点。 写模板时默认使用 C++17,变量名尽量短,但注释要说明不变量和适用条件。
1. 二维差分模板
矩形加法、多次操作后统一求值。
void add(int x1, int y1, int x2, int y2, int v) { d[x1][y1] += v; d[x2 + 1][y1] -= v; d[x1][y2 + 1] -= v; d[x2 + 1][y2 + 1] += v;}for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) a[i][j] = d[i][j] + a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];要点:
- 数组需要多开一圈。
- 适合离线多次矩形修改。
2. 扫描线处理区间事件
把区间转化为两个事件,按坐标排序扫描。
struct Event { int x, type, id; };vector<Event> ev;// [l, r] 加入事件:l 处 +1,r+1 处 -1sort(ev.begin(), ev.end(), [](auto& a, auto& b){ return a.x < b.x; });long long cur = 0;for (auto e : ev) { cur += e.type;}要点:
- 适合区间覆盖、会议室数量、差分思想推广。
- 二维矩形面积并需要线段树维护 y 方向覆盖长度。
3. 莫队算法
静态区间询问可离线排序,使左右指针移动总成本约为 。
int B;struct Query { int l, r, id; };sort(qs.begin(), qs.end(), [](const Query& a, const Query& b) { int A = a.l / B, C = b.l / B; if (A != C) return A < C; return (A & 1) ? a.r > b.r : a.r < b.r;});int L = 1, R = 0;for (auto qu : qs) { while (L > qu.l) add(--L); while (R < qu.r) add(++R); while (L < qu.l) del(L++); while (R > qu.r) del(R--); ans[qu.id] = cur;}要点:
- 适合 add/del 都容易维护的区间统计。
- 块大小通常取 。
常见坑:
- 带修改莫队更复杂,需要第三维时间。
- 如果 add/del 不可逆,不适合莫队。
4. 尺取法与单调队列 DP
双指针解决窗口可行性,单调队列还能优化 DP。
要点:
- 当候选 j 的合法范围随 i 单调移动时,可以用队列维护。
- 当转移值可比较且过期条件明确时,可用单调队列。
5. 前缀和 + 哈希
区间和等于 k 可转化为两个前缀和差值。
unordered_map<long long, int> cnt;cnt[0] = 1;long long s = 0, ans = 0;for (int x : a) { s += x; ans += cnt[s - k]; cnt[s]++;}要点:
- 可处理负数,因为不是滑动窗口。
- 统计方案数时先查再加当前前缀。
训练题型:
- 统计和为 k 的子数组数量。
- 统计异或为 k 的子数组数量。
本章模板背诵清单
- 能在 5 分钟内写出本章第一个核心模板。
- 能说出每个模板的时间复杂度和空间复杂度。
- 能说明模板不适用的反例。
- 能为模板构造 3 个边界样例。
- 能把模板改成 0-index 或 1-index 版本。
离线与根号分治
根号分治思想
当一个参数有大小之分时,按阈值 B 分成小规模暴力、大规模预处理。
- 出现频率大于 B 的元素最多 n/B 个。
- 小步长暴力,大步长预处理。
- 常见于询问按模数、步长、出现次数分类。
分块基础
把数组分成大小约 的块,块内暴力,整块维护信息。
- 适合不容易写线段树的区间问题。
- 修改局部重构整块。
- 莫队也是根号思想的一种应用。
二维扫描线面积并
矩形面积并:扫描 x 方向事件,用线段树维护 y 方向覆盖长度。
- 每个矩形产生左边 +1、右边 -1 两个事件。
- 相邻事件 x 差乘当前 y 覆盖长度。
- y 坐标需要离散化。
前缀最值优化枚举
很多二重枚举可把内层最优值转为前缀最大/最小。
- 当转移中 j 和 i 可拆开时优先尝试。
- 这是 DP 优化和贪心优化的常见入口。
离线查询按右端点排序
区间询问经常按右端点排序,边扫描边更新数据结构。
- 区间不同数个数。
- 最近相同位置贡献。
- 树状数组维护每个值最后出现位置。
高频模板训练卡
这一组训练卡用于把“04_枚举_前缀和_差分_双指针”转化为赛场识别能力。每张卡都包含题目信号、模板选择、复杂度、反例和实现检查。
卡 1:一维前缀和
- 题目信号:区间统计、批量修改或连续窗口中出现 一维前缀和 信号。
- 优先模板:优先尝试 一维前缀和。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 一维前缀和 解决一道区间题并写出为什么不会漏算。
卡 2:二维前缀和
- 题目信号:区间统计、批量修改或连续窗口中出现 二维前缀和 信号。
- 优先模板:优先尝试 二维前缀和。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 二维前缀和 解决一道区间题并写出为什么不会漏算。
卡 3:一维差分
- 题目信号:区间统计、批量修改或连续窗口中出现 一维差分 信号。
- 优先模板:优先尝试 一维差分。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 一维差分 解决一道区间题并写出为什么不会漏算。
卡 4:二维差分
- 题目信号:区间统计、批量修改或连续窗口中出现 二维差分 信号。
- 优先模板:优先尝试 二维差分。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 二维差分 解决一道区间题并写出为什么不会漏算。
卡 5:前缀异或
- 题目信号:区间统计、批量修改或连续窗口中出现 前缀异或 信号。
- 优先模板:优先尝试 前缀异或。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 前缀异或 解决一道区间题并写出为什么不会漏算。
卡 6:前缀和 + 哈希
- 题目信号:区间统计、批量修改或连续窗口中出现 前缀和 + 哈希 信号。
- 优先模板:优先尝试 前缀和 + 哈希。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 前缀和 + 哈希 解决一道区间题并写出为什么不会漏算。
卡 7:滑动窗口
- 题目信号:区间统计、批量修改或连续窗口中出现 滑动窗口 信号。
- 优先模板:优先尝试 滑动窗口。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 滑动窗口 解决一道区间题并写出为什么不会漏算。
卡 8:相向双指针
- 题目信号:区间统计、批量修改或连续窗口中出现 相向双指针 信号。
- 优先模板:优先尝试 相向双指针。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 相向双指针 解决一道区间题并写出为什么不会漏算。
卡 9:三指针
- 题目信号:区间统计、批量修改或连续窗口中出现 三指针 信号。
- 优先模板:优先尝试 三指针。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 三指针 解决一道区间题并写出为什么不会漏算。
卡 10:离散化
- 题目信号:区间统计、批量修改或连续窗口中出现 离散化 信号。
- 优先模板:优先尝试 离散化。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 离散化 解决一道区间题并写出为什么不会漏算。
卡 11:扫描线
- 题目信号:区间统计、批量修改或连续窗口中出现 扫描线 信号。
- 优先模板:优先尝试 扫描线。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 扫描线 解决一道区间题并写出为什么不会漏算。
卡 12:矩形面积并
- 题目信号:区间统计、批量修改或连续窗口中出现 矩形面积并 信号。
- 优先模板:优先尝试 矩形面积并。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 矩形面积并 解决一道区间题并写出为什么不会漏算。
卡 13:莫队
- 题目信号:区间统计、批量修改或连续窗口中出现 莫队 信号。
- 优先模板:优先尝试 莫队。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 莫队 解决一道区间题并写出为什么不会漏算。
卡 14:带修莫队
- 题目信号:区间统计、批量修改或连续窗口中出现 带修莫队 信号。
- 优先模板:优先尝试 带修莫队。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 带修莫队 解决一道区间题并写出为什么不会漏算。
卡 15:分块
- 题目信号:区间统计、批量修改或连续窗口中出现 分块 信号。
- 优先模板:优先尝试 分块。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 分块 解决一道区间题并写出为什么不会漏算。
卡 16:根号分治
- 题目信号:区间统计、批量修改或连续窗口中出现 根号分治 信号。
- 优先模板:优先尝试 根号分治。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 根号分治 解决一道区间题并写出为什么不会漏算。
卡 17:离线按右端点
- 题目信号:区间统计、批量修改或连续窗口中出现 离线按右端点 信号。
- 优先模板:优先尝试 离线按右端点。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 离线按右端点 解决一道区间题并写出为什么不会漏算。
卡 18:贡献法枚举
- 题目信号:区间统计、批量修改或连续窗口中出现 贡献法枚举 信号。
- 优先模板:优先尝试 贡献法枚举。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 贡献法枚举 解决一道区间题并写出为什么不会漏算。
卡 19:子数组计数
- 题目信号:区间统计、批量修改或连续窗口中出现 子数组计数 信号。
- 优先模板:优先尝试 子数组计数。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 子数组计数 解决一道区间题并写出为什么不会漏算。
卡 20:区间众数近似
- 题目信号:区间统计、批量修改或连续窗口中出现 区间众数近似 信号。
- 优先模板:优先尝试 区间众数近似。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 区间众数近似 解决一道区间题并写出为什么不会漏算。
卡 21:小大分类
- 题目信号:区间统计、批量修改或连续窗口中出现 小大分类 信号。
- 优先模板:优先尝试 小大分类。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 小大分类 解决一道区间题并写出为什么不会漏算。
卡 22:bitset 批量枚举
- 题目信号:区间统计、批量修改或连续窗口中出现 bitset 批量枚举 信号。
- 优先模板:优先尝试 bitset 批量枚举。
- 核心不变量:扫描过程中已处理部分的信息能完整回答当前问题。
- 复杂度目标:目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。
- 不适用场景:窗口不单调、修改在线强制、信息无法撤销时不适用。
- 实现检查:检查区间开闭、数组多开一位、离散化后是否保留长度。
- 边界样例:空区间、单点区间、全覆盖、负数、重复坐标。
- 训练题型:用 bitset 批量枚举 解决一道区间题并写出为什么不会漏算。
本章赛前默写任务
- 默写 一维前缀和 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 二维前缀和 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 一维差分 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 二维差分 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 前缀异或 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 前缀和 + 哈希 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 滑动窗口 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 相向双指针 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 三指针 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 默写 离散化 的模板,并写出 目标 O(n)、O(n log n) 或 O((n+q)sqrt n)。。
- 为本章任选 3 个模板各写一个最小输入。
- 为本章任选 3 个模板各写一个会使错误实现失败的反例。
- 把本章所有模板整理到个人代码库,并标注 0-index / 1-index。
04_枚举_前缀和_差分_双指针:详细训练清单
本清单用于把章节知识拆成可执行的小任务,偏 OI/ACM 赛场使用。
训练点 1:暴力枚举降维
- 识别信号:题面出现与“暴力枚举降维”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“暴力枚举降维”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 2:贡献法
- 识别信号:题面出现与“贡献法”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“贡献法”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 3:一维前缀和
- 识别信号:题面出现与“一维前缀和”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“一维前缀和”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 4:二维前缀和
- 识别信号:题面出现与“二维前缀和”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“二维前缀和”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 5:前缀异或
- 识别信号:题面出现与“前缀异或”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“前缀异或”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 6:前缀哈希计数
- 识别信号:题面出现与“前缀哈希计数”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“前缀哈希计数”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 7:一维差分
- 识别信号:题面出现与“一维差分”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“一维差分”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 8:二维差分
- 识别信号:题面出现与“二维差分”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“二维差分”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 9:相向双指针
- 识别信号:题面出现与“相向双指针”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“相向双指针”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 10:滑动窗口
- 识别信号:题面出现与“滑动窗口”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“滑动窗口”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 11:离散化
- 识别信号:题面出现与“离散化”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“离散化”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 12:扫描线
- 识别信号:题面出现与“扫描线”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“扫描线”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 13:莫队
- 识别信号:题面出现与“莫队”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“莫队”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 14:分块
- 识别信号:题面出现与“分块”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“分块”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 15:根号分治
- 识别信号:题面出现与“根号分治”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“根号分治”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 16:离线查询
- 识别信号:题面出现与“离线查询”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“离线查询”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 17:暴力枚举降维
- 识别信号:题面出现与“暴力枚举降维”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“暴力枚举降维”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 18:贡献法
- 识别信号:题面出现与“贡献法”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“贡献法”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 19:一维前缀和
- 识别信号:题面出现与“一维前缀和”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“一维前缀和”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 20:二维前缀和
- 识别信号:题面出现与“二维前缀和”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“二维前缀和”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
训练点 21:前缀异或
- 识别信号:题面出现与“前缀异或”相关的限制、操作或查询时,先判断能否套用本章模型。
- 建模步骤:写出输入对象、维护状态、允许操作、目标答案,再决定使用暴力、模板或优化。
- 模板要求:能默写核心代码,并说明变量含义、初始化方式和循环边界。
- 复杂度要求:写出预处理、单次操作、总复杂度,并确认能通过最大数据范围。
- 反例检查:构造最小规模、全相等、极端值、重复值、无解或刚好可行的样例。
- 复盘要求:若做错,记录错因是建模、证明、复杂度、边界、溢出还是模板不熟。
- 扩展任务:把“前缀异或”与至少一个其他专题组合,例如二分、图论、DP、数据结构或数学。
如果這篇文章對你有幫助,歡迎分享給更多人!
部分資訊可能已經過時





















