C++ 竞赛中时间复杂度与数据规模的关系

核心经验法则
1 秒大约能执行 10⁸ 次基本运算(C++,O2 优化下)
这是所有判断的基础。竞赛中常见时限为 1s 或 2s。
一、数据规模 → 可接受的最高复杂度
| 数据规模 nnn | 可接受的复杂度 | 典型算法举例 |
|---|---|---|
| n≤10n \leq 10n≤10 | O(n!)O(n!)O(n!), O(2n⋅n)O(2^n \cdot n)O(2n⋅n) | 全排列、状态压缩 DP |
| n≤20n \leq 20n≤20 | O(2n)O(2^n)O(2n) | 状压 DP、折半搜索 |
| n≤30n \leq 30n≤30 | O(2n)O(2^n)O(2n) 勉强 / O(n⋅2n/2)O(n \cdot 2^{n/2})O(n⋅2n/2) | 折半枚举 |
| n≤50n \leq 50n≤50 | O(n4)O(n^4)O(n4) | 区间 DP |
| n≤200n \leq 200n≤200 | O(n3)O(n^3)O(n3) | Floyd、普通 DP |
| n≤1000n \leq 1000n≤1000 | O(n2logn)O(n^2 \log n)O(n2logn) | 二维 DP + 排序 |
| n≤104n \leq 10^4n≤104 | O(n2)O(n^2)O(n2) | 冒泡排序、朴素 DP |
| n≤105n \leq 10^5n≤105 | O(nlogn)O(n \log n)O(nlogn) | 排序、线段树、树剖 |
| n≤106n \leq 10^6n≤106 | O(n)O(n)O(n) 或 O(nlogn)O(n \log n)O(nlogn) 勉强 | 线性扫描、前缀和 |
| n≤107n \leq 10^7n≤107 | O(n)O(n)O(n)(要写快) | 筛法、桶排序 |
| n≤108n \leq 10^8n≤108 | O(n)O(n)O(n) 极限 | 一次性线性扫描 |
| n≥109n \geq 10^9n≥109 | O(n)O(\sqrt{n})O(n ), O(logn)O(\log n)O(logn), O(1)O(1)O(1) | 数论分块、二分、数学公式 |
二、快速心算公式
所需时间≈运算次数108 秒\text{所需时间} \approx \frac{\text{运算次数}}{10^8} \text{ 秒}所需时间≈108运算次数 秒
举例:
- n=105n = 10^5n=105,O(n2)O(n^2)O(n2) → 101010^{10}1010 次运算 → 100 秒,超时
- n=105n = 10^5n=105,O(nlogn)O(n \log n)O(nlogn) → 105×17≈1.7×10610^5 \times 17 \approx 1.7 \times 10^6105×17≈1.7×106 → 0.017 秒,安全
- n=106n = 10^6n=106,O(n)O(n)O(n) → 10610^6106 次 → 0.01 秒,安全
- n=109n = 10^9n=109,O(n)O(\sqrt{n})O(n ) → 3×1043 \times 10^43×104 次 → 极快
三、常见复杂度的运算次数速查
以 n=105n = 10^5n=105 为例:
| 复杂度 | 运算次数 | 1s 内能否通过 |
|---|---|---|
| O(logn)O(\log n)O(logn) | ∼17\sim 17∼17 | 轻松 |
| O(n)O(\sqrt{n})O(n ) | ∼316\sim 316∼316 | 轻松 |
| O(n)O(n)O(n) | 10510^5105 | 轻松 |
| O(nlogn)O(n \log n)O(nlogn) | ∼1.7×106\sim 1.7 \times 10^6∼1.7×106 | 轻松 |
| O(nn)O(n \sqrt{n})O(nn ) | ∼3×107\sim 3 \times 10^7∼3×107 | 勉强 |
| O(n2)O(n^2)O(n2) | 101010^{10}1010 | 超时 |
| O(n3)O(n^3)O(n3) | 101510^{15}1015 | 严重超时 |
四、实战判断流程
拿到题目
│
▼
看数据范围 n
│
├─ n ≤ 20 → 想指数级(搜索/状压)
├─ n ≤ 500 → 想 O(n³)(Floyd/区间DP)
├─ n ≤ 10⁴ → 想 O(n²)(朴素DP)
├─ n ≤ 10⁵ → 想 O(n log n)(排序/线段树/二分)
├─ n ≤ 10⁶ → 想 O(n)(贪心/双指针/单调栈)
└─ n ≥ 10⁸ → 想 O(log n) 或 O(1)(数学/二分)
五、容易踩的坑
-
多组数据 :题目说 TTT 组询问,总复杂度要乘以 TTT。比如 T=105T = 10^5T=105,每组只能做 O(logn)O(\log n)O(logn) 或 O(1)O(1)O(1)。
-
隐含的常数 :同样是 O(nlogn)O(n \log n)O(nlogn),线段树常数比
sort大好几倍,要注意。 -
STL 的隐藏复杂度 :
map是 O(logn)O(\log n)O(logn) 但常数大,unordered_map均摊 O(1)O(1)O(1) 但有最坏 O(n)O(n)O(n) 的风险。 -
内存限制 :n=107n = 10^7n=107 的
int数组约 40MB,n=108n = 10^8n=108 约 400MB,可能 MLE。
六、记忆口诀
十的八次方是一秒,对数永远不用急,平方过万要小心,指数二十是上限。
希望这个总结对你有帮助,比赛时拿到题先看 nnn 的范围,就能快速锁定该用什么复杂度的算法了。