初学者预备知识

看各专题前先把这些"地基"打牢:复杂度估算、STL、取模、文件读写、对拍

一、复杂度估算:10⁸ 法则

估算复杂度时可用 10⁸ 次量级作粗略参照;硬件、语言、访存和操作类型都会影响速度,不能把它当作固定的每秒吞吐量。拿到题目先看数据范围,反推能用什么复杂度的算法——这是选题方向的第一判断:

n 的规模候选复杂度(需估算)典型算法
n ≤ 20O(2ⁿ · n),或优化后的 O(2ⁿ · n²)状压 DP、爆搜 + 剪枝
n ≤ 400O(n³)Floyd、区间 DP
n ≤ 5000O(n²)二维 DP、中心扩展
n ≤ 2×10⁵O(n log n)排序 + 堆 / 二分 / 线段树 / 树形 DP
n ≤ 10⁶ ~ 10⁷O(n)Manacher、AC 自动机、双指针
口诀:看到 20 想状压,看到 400 想三方,看到 10⁵ 想 log,看到 10⁷ 必须线性。算完复杂度再动手写代码。

二、STL 速查(考场最常用的六件工具)

工具声明核心操作用途
动态数组vector<int> a;push_back / size / a[i]邻接表 vector<int> g[N]、一切变长数据
排序sort(a, a+n); sort(v.begin(), v.end(), cmp);贪心第一步、离散化
二分查找lower_bound(v.begin(), v.end(), x)离散化求排名、有序数组查找
队列queue<int> q;push / front / pop / emptyBFS
栈stack<int> s;push / top / pop括号匹配、单调栈
集合/映射set<int> / map<int,int>insert / count / find动态维护有序集合,O(log n)

比赛允许 #include <bits/stdc++.h> 一个头文件包含全部 STL。

三、堆(优先队列):反悔贪心的武器

堆是一棵满足"父 ≤ 子(小根堆)"的完全二叉树,支持两个操作,都是 O(log n):

priority_queue<int> big;                              // 大根堆(默认,堆顶最大)
priority_queue<int, vector<int>, greater<int>> small;  // 小根堆(堆顶最小)
small.push(x); small.pop();                             // O(log n)
small.top();                                          // O(1),仅访问堆顶
生活类比:医院急诊叫号屏永远显示"当前最紧急"的病人。新病人来了按紧急程度插入队伍,屏上自动更新——你不需要知道队伍内部怎么排,只要知道屏上永远是最紧急的。这就是堆。

懒删除技巧:堆不支持"删除任意元素"。变通做法:要删的元素先打个标记,等它浮到堆顶时再跳过(见于 种树、Dijkstra)。

四、取模与 long long:爆零重灾区

五、文件读写:freopen 与防爆零

CSP-S 复赛是 文件 IO:从 xxx.in 读入、向 xxx.out 输出(xxx 是题目英文标识)。程序开头固定写:

int main() {
    freopen("game.in", "r", stdin);
    freopen("game.out", "w", stdout);
    // ... 正常用 scanf/printf 或 cin/cout
    return 0;
}
每年都有人因此爆零:① 文件名与题目英文标识不一致(大小写也要一致);② 调试时注释掉 freopen,提交前忘改回;③ 提交目录里留了 .in/.out/可执行文件。考前把防爆零清单过一遍。

读入加速:数据量 ≥ 10⁶ 时用 scanf/printf,或 cin 前加 ios::sync_with_stdio(false); cin.tie(nullptr);(加完不要再混用 scanf)。

六、对拍:找 bug 的终极武器

写完一个"聪明做法"但不确定对不对?再写一个笨但显然正确的暴力版,用随机数据比对两者输出:

  1. 暴力版 brute.cpp:O(n²) 甚至 O(n!) 都行,只要逻辑简单到不可能错。
  2. 数据生成器 gen.cpp:随机出小规模合法输入(小数据才能让暴力跑得动)。
  3. 对拍脚本:循环执行 gen → 两份程序 → diff 比对,输出不同就停下保留现场。
# bash 对拍循环
while true; do
  ./gen > in.txt
  ./a < in.txt > out1.txt
  ./brute < in.txt > out2.txt
  diff out1.txt out2.txt || { echo "FOUND!"; break; }
done

对拍 10 分钟,胜过盯代码 1 小时。大模拟和计数 DP 这类"看起来对"的题尤其需要。

七、配套小测(10 题,即时判分)