1. 快速排序(分治思想)
voidquickSort(int a[], int l, int r){if (l >= r) return;int i = l - 1, j = r + 1, x = a[l + r >> 1];while (i < j) {do i++; while (a[i] < x);do j--; while (a[j] > x);if (i < j) swap(a[i], a[j]);}quickSort(a, l, j);quickSort(a, j + 1, r);}
2. 归并排序(求逆序对)
int tmp[N];longlongmergeSort(int a[], int l, int r) {if (l >= r) return 0;int mid = l + r >> 1;long long res = mergeSort(a, l, mid) + mergeSort(a, mid + 1, r);int i = l, j = mid + 1, k = 0;while (i <= mid && j <= r) {if (a[i] <= a[j]) tmp[k++] = a[i++];else {tmp[k++] = a[j++];res += mid - i + 1; // 统计逆序对}}while (i <= mid) tmp[k++] = a[i++];while (j <= r) tmp[k++] = a[j++];for (i = l, k = 0; i <= r; i++, k++) a[i] = tmp[k];return res;}
3. 二分查找(整数/实数)
// 整数二分:在升序数组中找到第一个 >= x 的位置intlower_bound(int a[], int n, int x) {int l = 0, r = n - 1, ans = n;while (l <= r) {int mid = l + r >> 1;if (a[mid] >= x) ans = mid, r = mid - 1;else l = mid + 1;}return ans;}// 实数二分:求 sqrt(2) 的近似值doublesqrt2() {double l = 1, r = 2;for (int i = 0; i < 100; i++) { // 循环固定次数double mid = (l + r) / 2;if (mid * mid > 2) r = mid;else l = mid;}return l;}
4. 高精度加法(vector存储)
vector<int> add(vector<int> &A, vector<int> &B){vector<int> C;int t = 0;for (int i = 0; i < A.size() || i < B.size() || t; i++) {if (i < A.size()) t += A[i];if (i < B.size()) t += B[i];C.push_back(t % 10);t /= 10;}return C;}
5. DFS(全排列)
int n, path[N];bool st[N];voiddfs(int u) {if (u == n) {for (int i = 0; i < n; i++) cout << path[i] << ' ';cout << '\n';return;}for (int i = 1; i <= n; i++) {if (!st[i]) {path[u] = i;st[i] = true;dfs(u + 1);st[i] = false;}}}
6. BFS(迷宫最短路)
int g[N][N], dist[N][N];int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};intbfs(int sx, int sy, int tx, int ty){memset(dist, -1, sizeof dist);queue<pair<int,int>> q;q.push({sx, sy});dist[sx][sy] = 0;while (q.size()) {auto [x, y] = q.front(); q.pop();if (x == tx && y == ty) return dist[x][y];for (int i = 0; i < 4; i++) {int nx = x + dx[i], ny = y + dy[i];if (nx>=0 && nx<n && ny>=0 && ny<n && g[nx][ny]==0 && dist[nx][ny]==-1) {dist[nx][ny] = dist[x][y] + 1;q.push({nx, ny});}}}return -1;}
7. 前缀和与差分
// 一维前缀和int a[N], s[N];for (int i = 1; i <= n; i++) s[i] = s[i-1] + a[i];// 查询 [l, r] 的和:s[r] - s[l-1]// 一维差分(区间加)int d[N];voidadd(int l, int r, int c) {d[l] += c;d[r+1] -= c;}// 最后求前缀和得到原数组for (int i = 1; i <= n; i++) d[i] += d[i-1];
8. 01背包(倒序枚举容量)
int dp[M];for (int i = 1; i <= n; i++) {int v, w; cin >> v >> w;for (int j = m; j >= v; j--)dp[j] = max(dp[j], dp[j - v] + w);}cout << dp[m];
9. LCS(最长公共子序列)
char a[N], b[N];int f[N][N];for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)if (a[i] == b[j]) f[i][j] = f[i-1][j-1] + 1;else f[i][j] = max(f[i-1][j], f[i][j-1]);
进阶算法模板 (CSP-S冲刺)
10. 堆优化Dijkstra
typedef pair<int,int> PII;vector<PII> g[N];int dist[N];bool vis[N];voiddijkstra(int s){memset(dist, 0x3f, sizeof dist);priority_queue<PII, vector<PII>, greater<PII>> pq;dist[s] = 0;pq.push({0, s});while (pq.size()) {auto [d, u] = pq.top(); pq.pop();if (vis[u]) continue;vis[u] = true;for (auto [v, w] : g[u]) {if (dist[v] > dist[u] + w) {dist[v] = dist[u] + w;pq.push({dist[v], v});}}}}
11. SPFA(判负环)
int dist[N], cnt[N];bool inq[N];bool spfa(int n, int s) { // 返回true表示有负环memset(dist, 0x3f, sizeof dist);queue<int> q;dist[s] = 0; q.push(s); inq[s] = true;while (q.size()) {int u = q.front(); q.pop(); inq[u] = false;for (auto [v, w] : g[u]) {if (dist[v] > dist[u] + w) {dist[v] = dist[u] + w;cnt[v] = cnt[u] + 1;if (cnt[v] >= n) return true; // 有负环if (!inq[v]) q.push(v), inq[v] = true;}}}return false;}
12. Kruskal(最小生成树)
struct Edge { int u, v, w; } e[M];int fa[N];int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }int kruskal(int n, int m) {sort(e, e + m, [](Edge a, Edge b){ return a.w < b.w; });for (int i = 1; i <= n; i++) fa[i] = i;int res = 0, cnt = 0;for (int i = 0; i < m; i++) {int fu = find(e[i].u), fv = find(e[i].v);if (fu != fv) {fa[fu] = fv;res += e[i].w;cnt++;}if (cnt == n - 1) break;}return cnt == n - 1 ? res : -1; // -1表示不连通}
13. Tarjan(求强连通分量)
int dfn[N], low[N], idx, stk[N], top;bool ins[N];int scc[N], scnt;voidtarjan(int u) {dfn[u] = low[u] = ++idx;stk[++top] = u; ins[u] = true;for (int v : g[u]) {if (!dfn[v]) {tarjan(v);low[u] = min(low[u], low[v]);} else if (ins[v])low[u] = min(low[u], dfn[v]);}if (dfn[u] == low[u]) {scnt++;int y;do {y = stk[top--];ins[y] = false;scc[y] = scnt;} while (y != u);}}
14. 并查集(路径压缩+按秩合并)
int fa[N], sz[N];voidinit(int n){for (int i = 1; i <= n; i++) fa[i] = i, sz[i] = 1;}intfind(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]); }voidunite(int a, int b){a = find(a); b = find(b);if (a == b) return;if (sz[a] < sz[b]) swap(a, b);fa[b] = a;sz[a] += sz[b];}
15. 树状数组(单点加,区间和)
int tr[N];int n;int lowbit(int x) { return x & -x; }void add(int x, int v) {for (; x <= n; x += lowbit(x)) tr[x] += v;}int sum(int x) {int res = 0;for (; x > 0; x -= lowbit(x)) res += tr[x];return res;}int range_sum(int l, int r) { return sum(r) - sum(l-1); }
16. 线段树(区间加+区间求和)
struct SegTree {int l, r;long long sum, add;} tr[N * 4];voidbuild(int u, int l, int r) {tr[u] = {l, r, 0, 0};if (l == r) return;int mid = l + r >> 1;build(u<<1, l, mid);build(u<<1|1, mid+1, r);}voidpushup(int u) {tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;}voidpushdown(int u) {if (tr[u].add) {auto &root = tr[u], &left = tr[u<<1], &right = tr[u<<1|1];left.add += root.add;left.sum += (left.r - left.l + 1) * root.add;right.add += root.add;right.sum += (right.r - right.l + 1) * root.add;root.add = 0;}}voidmodify(int u, int l, int r, int v) {if (tr[u].l >= l && tr[u].r <= r) {tr[u].sum += (tr[u].r - tr[u].l + 1) * v;tr[u].add += v;return;}pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid) modify(u<<1, l, r, v);if (r > mid) modify(u<<1|1, l, r, v);pushup(u);}longlongquery(int u, int l, int r) {if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;pushdown(u);int mid = tr[u].l + tr[u].r >> 1;long long res = 0;if (l <= mid) res += query(u<<1, l, r);if (r > mid) res += query(u<<1|1, l, r);return res;}
17. 快速幂(a^b mod p)
long long qpow(longlong a, longlong b, longlong p) {long long res = 1;while (b) {if (b & 1) res = res * a % p;a = a * a % p;b >>= 1;}return res;}
18. 扩展欧几里得(exgcd)
intexgcd(int a, int b, int &x, int &y) {if (!b) { x = 1; y = 0; return a; }int d = exgcd(b, a % b, y, x);y -= a / b * x;return d;}// 返回gcd,且x,y满足 a*x + b*y = gcd(a,b)
19. 线性筛(欧拉筛)
int primes[N], cnt;bool st[N];voidget_primes(int n) {for (int i = 2; i <= n; i++) {if (!st[i]) primes[cnt++] = i;for (int j = 0; primes[j] <= n / i; j++) {st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}}
高阶算法模板(NOI/省选参考)
20. KMP(字符串匹配)
char s[N], p[N];int ne[N];voidbuild_next(){int n = strlen(p + 1);for (int i = 2, j = 0; i <= n; i++) {while (j && p[i] != p[j+1]) j = ne[j];if (p[i] == p[j+1]) j++;ne[i] = j;}}voidkmp(){int n = strlen(s + 1), m = strlen(p + 1);for (int i = 1, j = 0; i <= n; i++) {while (j && s[i] != p[j+1]) j = ne[j];if (s[i] == p[j+1]) j++;if (j == m) {// 匹配成功,位置 i-m+1j = ne[j];}}}
21. Trie(字典树)
int son[N][26], cnt[N], idx;void insert(char *str) {int p = 0;for (int i = 0; str[i]; i++) {int u = str[i] - 'a';if (!son[p][u]) son[p][u] = ++idx;p = son[p][u];}cnt[p]++;}int query(char *str) {int p = 0;for (int i = 0; str[i]; i++) {int u = str[i] - 'a';if (!son[p][u]) return 0;p = son[p][u];}return cnt[p];}
22. LCA(倍增法)
int depth[N], fa[N][20];vector<int> g[N];voidbfs(int root){memset(depth, 0x3f, sizeof depth);depth[0] = 0; depth[root] = 1;queue<int> q; q.push(root);while (q.size()) {int u = q.front(); q.pop();for (int v : g[u]) {if (depth[v] > depth[u] + 1) {depth[v] = depth[u] + 1;q.push(v);fa[v][0] = u;for (int k = 1; k <= 19; k++)fa[v][k] = fa[fa[v][k-1]][k-1];}}}}intlca(int a, int b){if (depth[a] < depth[b]) swap(a, b);for (int k = 19; k >= 0; k--)if (depth[fa[a][k]] >= depth[b])a = fa[a][k];if (a == b) return a;for (int k = 19; k >= 0; k--)if (fa[a][k] != fa[b][k])a = fa[a][k], b = fa[b][k];return fa[a][0];}
以上是CSP常用的算法模板。建议您亲手将每个模板敲一遍,理解每一行的作用,并根据自己的编码风格稍作调整。建立自己的代码库后,配合真题反复练习,考场上就能快速调用、不易出错。
夜雨聆风