C++ 竞赛常用算法模板速查表
------彭彭老师
内容涵盖了以下 11 大模块:
| 模块 | 内容 |
|---|---|
| 一、基础工具 | 快速 I/O、GCD/LCM、快速幂、组合数预处理 |
| 二、素数相关 | 素数判断、埃氏筛、线性筛(欧拉筛)、区间筛 |
| 三、排序算法 | 快速排序(手写)、归并排序(含逆序对)、STL sort |
| 四、二分查找 | 整数二分(左右边界)、实数二分、二分答案 |
| 五、前缀和与差分 | 一维/二维前缀和、一维/二维差分 |
| 六、双指针 | 对撞指针、快慢指针 |
| 七、贪心算法 | 区间贪心 |
| 八、递归与分治 | 分治思想回顾 |
| 九、常用 STL 速查 | vector/sort/lower_bound/优先队列/map 等 |
| 十、动态规划基础 | 0/1背包、完全背包、LIS、LCS |
| 十一、数学公式速查 | 数列求和、排列组合、容斥原理、卡特兰数等 |
具体如下:
📚 C++ 算法竞赛常用模板速查表
这份速查表涵盖了基础工具、数论、排序、二分、数据结构、动态规划等核心模块,适用于 OI/ACM/ICPC 等算法竞赛复习。
一、基础工具
1. 快速输入输出 (IO 优化)
cpp
#include <iostream>
using namespace std;
int main() {
// 关闭 C 和 C++ 标准流的同步,大幅提升 cin/cout 速度
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
cout << n << endl;
return 0;
}
2. 最大公约数与最小公倍数
cpp
#include <numeric> // C++17 起包含 gcd/lcm
using namespace std;
// 手写 GCD (欧几里得算法)
long long gcd(long long a, long long b) {
return b == 0 ? a : gcd(b, a % b);
}
// 手写 LCM
long long lcm(long long a, long long b) {
return a / gcd(a, b) * b; // 先除后乘防止溢出
}
3. 快速幂
计算 ab(modp)a^b \pmod pab(modp),时间复杂度 O(logb)O(\log b)O(logb)。
cpp
long long qpow(long long a, long long b, long long p) {
long long res = 1 % p;
a %= p;
while (b) {
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
4. 组合数预处理 (杨辉三角)
适用于 n,mn, mn,m 较小(如 n≤5000n \le 5000n≤5000)的情况。
cpp
const int MAXN = 5005;
long long C[MAXN][MAXN];
void init_comb() {
for (int i = 0; i < MAXN; i++) {
C[i][0] = C[i][i] = 1;
for (int j = 1; j < i; j++) {
C[i][j] = (C[i-1][j] + C[i-1][j-1]); // 若需取模在此处 % MOD
}
}
}
二、素数相关
1. 素数判断 (试除法)
时间复杂度 O(n)O(\sqrt{n})O(n )。
cpp
bool is_prime(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
2. 埃拉托斯特尼筛法 (埃氏筛)
时间复杂度 O(nloglogn)O(n \log \log n)O(nloglogn)。
cpp
const int MAXN = 1000005;
bool is_prime[MAXN];
void sieve(int n) {
fill(is_prime, is_prime + n + 1, true);
is_prime[0] = is_prime[1] = false;
for (int i = 2; i * i <= n; i++) {
if (is_prime[i]) {
for (int j = i * i; j <= n; j += i) {
is_prime[j] = false;
}
}
}
}
3. 线性筛 (欧拉筛)
时间复杂度 O(n)O(n)O(n),同时可求出最小质因子。
cpp
const int MAXN = 1000005;
int primes[MAXN], cnt;
bool is_composite[MAXN];
void linear_sieve(int n) {
for (int i = 2; i <= n; i++) {
if (!is_composite[i]) primes[cnt++] = i;
for (int j = 0; j < cnt && i * primes[j] <= n; j++) {
is_composite[i * primes[j]] = true;
if (i % primes[j] == 0) break; // 关键:保证每个合数只被其最小质因子筛掉
}
}
}
三、排序算法
1. 快速排序 (手写)
cpp
void quick_sort(int q[], int l, int r) {
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j) {
do i++; while (q[i] < x);
do j--; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
2. 归并排序 (含逆序对统计)
cpp
long long merge_sort(int q[], int tmp[], int l, int r) {
if (l >= r) return 0;
int mid = l + r >> 1;
long long res = merge_sort(q, tmp, l, mid) + merge_sort(q, tmp, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r) {
if (q[i] <= q[j]) tmp[k++] = q[i++];
else {
tmp[k++] = q[j++];
res += mid - i + 1; // 统计逆序对
}
}
while (i <= mid) tmp[k++] = q[i++];
while (j <= r) tmp[k++] = q[j++];
for (i = l, k = 0; i <= r; i++, k++) q[i] = tmp[k];
return res;
}
3. STL Sort
cpp
#include <algorithm>
#include <vector>
using namespace std;
vector<int> v = {3, 1, 4, 1, 5};
sort(v.begin(), v.end()); // 升序
sort(v.begin(), v.end(), greater<int>()); // 降序
四、二分查找
1. 整数二分 (查找左边界/第一个 >= x 的位置)
cpp
int binary_search_left(int q[], int n, int x) {
int l = 0, r = n - 1;
while (l < r) {
int mid = l + r >> 1;
if (q[mid] >= x) r = mid;
else l = mid + 1;
}
return (q[l] == x) ? l : -1;
}
2. 实数二分
cpp
double binary_search_double(double l, double r) {
for (int i = 0; i < 100; i++) { // 循环 100 次精度足够
double mid = (l + r) / 2;
if (check(mid)) r = mid; // check 是判断条件
else l = mid;
}
return l;
}
五、前缀和与差分
1. 一维前缀和
cpp
int s[MAXN]; // s[i] = a[1] + ... + a[i]
// 区间和 [l, r] = s[r] - s[l-1]
2. 二维前缀和
cpp
int s[MAXN][MAXN];
// s[i][j] 表示从 (1,1) 到 (i,j) 的矩形和
// 初始化: s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j]
// 查询子矩阵 (x1,y1) 到 (x2,y2):
// sum = s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1]
3. 一维差分
cpp
// b[i] = a[i] - a[i-1]
// 给区间 [l, r] 加上 c: b[l] += c, b[r+1] -= c
// 最后对 b 求前缀和还原 a
六、双指针
1. 对撞指针 (Two Pointers)
常用于有序数组中找两数之和。
cpp
int i = 0, j = n - 1;
while (i < j) {
if (a[i] + a[j] == target) { /* found */ break; }
else if (a[i] + a[j] < target) i++;
else j--;
}
七、贪心算法
1. 区间调度 (按右端点排序)
cpp
struct Interval {
int l, r;
bool operator<(const Interval &t) const {
return r < t.r; // 按右端点升序
}
};
// 排序后依次选择不重叠的区间
八、递归与分治
1. 分治求最大值
cpp
int find_max(int q[], int l, int r) {
if (l == r) return q[l];
int mid = l + r >> 1;
return max(find_max(q, l, mid), find_max(q, mid + 1, r));
}
九、常用 STL 速查
| 容器/函数 | 用法 | 复杂度 |
|---|---|---|
vector<int> v |
v.push_back(x), v.size() |
O(1)O(1)O(1) 均摊 |
sort(v.begin(), v.end()) |
排序 | O(nlogn)O(n \log n)O(nlogn) |
lower_bound |
找第一个 ≥x\ge x≥x 的位置 | O(logn)O(\log n)O(logn) |
priority_queue<int> |
大根堆 | 插入/删除 O(logn)O(\log n)O(logn) |
map<int, int> |
红黑树实现 | 插入/查找 O(logn)O(\log n)O(logn) |
unordered_map |
哈希表实现 | 插入/查找 O(1)O(1)O(1) 平均 |
十、动态规划基础
1. 0/1 背包
cpp
int dp[MAXW]; // dp[j] 表示容量为 j 的最大价值
for (int i = 0; i < n; i++) {
for (int j = W; j >= w[i]; j--) { // 倒序遍历
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
2. 完全背包
cpp
for (int i = 0; i < n; i++) {
for (int j = w[i]; j <= W; j++) { // 正序遍历
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
}
}
3. 最长上升子序列 (LIS) - O(n2)O(n^2)O(n2)
cpp
int dp[MAXN]; // dp[i] 表示以 a[i] 结尾的 LIS 长度
for (int i = 0; i < n; i++) {
dp[i] = 1;
for (int j = 0; j < i; j++) {
if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1);
}
}
十一、数学公式速查
1. 等差数列求和
Sn=n(a1+an)2S_n = \frac{n(a_1 + a_n)}{2}Sn=2n(a1+an)
2. 等比数列求和
Sn=a11−qn1−q(q≠1)S_n = a_1 \frac{1-q^n}{1-q} \quad (q \neq 1)Sn=a11−q1−qn(q=1)
3. 排列组合
- 排列:Anm=n!(n−m)!A_n^m = \frac{n!}{(n-m)!}Anm=(n−m)!n!
- 组合:Cnm=n!m!(n−m)!C_n^m = \frac{n!}{m!(n-m)!}Cnm=m!(n−m)!n!
- 性质:Cnm=Cnn−mC_n^m = C_n^{n-m}Cnm=Cnn−m, Cnm=Cn−1m+Cn−1m−1C_n^m = C_{n-1}^m + C_{n-1}^{m-1}Cnm=Cn−1m+Cn−1m−1
4. 容斥原理
∣A∪B∣=∣A∣+∣B∣−∣A∩B∣|A \cup B| = |A| + |B| - |A \cap B|∣A∪B∣=∣A∣+∣B∣−∣A∩B∣
5. 卡特兰数
Cn=1n+1C2nnC_n = \frac{1}{n+1} C_{2n}^nCn=n+11C2nn
应用:出栈序列数、二叉树形态数等。