快速排序

  1. void quick_sort(int q[], int l, int r)
  2. {
  3. if (l >= r) return;
  4. int i = l - 1, j = r + 1, x = q[l + r >> 1];
  5. while (i < j)
  6. {
  7. do i ++ ; while (q[i] < x);
  8. do j -- ; while (q[j] > x);
  9. if (i < j) swap(q[i], q[j]);
  10. }
  11. quick_sort(q, l, j), quick_sort(q, j + 1, r);
  12. }

归并排序

  1. void merge_sort(int q[], int l, int r)
  2. {
  3. if (l >= r) return;
  4. int mid = l + r >> 1;
  5. merge_sort(q, l, mid);
  6. merge_sort(q, mid + 1, r);
  7. int k = 0, i = l, j = mid + 1;
  8. while (i <= mid && j <= r)
  9. if (q[i] <= q[j]) tmp[k ++ ] = q[i ++ ];
  10. else tmp[k ++ ] = q[j ++ ];
  11. while (i <= mid) tmp[k ++ ] = q[i ++ ];
  12. while (j <= r) tmp[k ++ ] = q[j ++ ];
  13. for (i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
  14. }

整数二分

  1. bool check(int x) {/* ... */} // 检查x是否满足某种性质
  2. // 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
  3. int bsearch_1(int l, int r)
  4. {
  5. while (l < r)
  6. {
  7. int mid = l + r >> 1;
  8. if (check(mid)) r = mid; // check()判断mid是否满足性质
  9. else l = mid + 1;
  10. }
  11. return l;
  12. }
  13. // 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
  14. int bsearch_2(int l, int r)
  15. {
  16. while (l < r)
  17. {
  18. int mid = l + r + 1 >> 1;
  19. if (check(mid)) l = mid;
  20. else r = mid - 1;
  21. }
  22. return l;
  23. }

浮点数二分

  1. bool check(double x) {/* ... */} // 检查x是否满足某种性质
  2. double bsearch_3(double l, double r)
  3. {
  4. const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
  5. while (r - l > eps)
  6. {
  7. double mid = (l + r) / 2;
  8. if (check(mid)) r = mid;
  9. else l = mid;
  10. }
  11. return l;
  12. }

高精度加法

  1. // C = A + B, A >= 0, B >= 0
  2. vector<int> add(vector<int> &A, vector<int> &B)
  3. {
  4. if (A.size() < B.size()) return add(B, A);
  5. vector<int> C;
  6. int t = 0;
  7. for (int i = 0; i < A.size(); i ++ )
  8. {
  9. t += A[i];
  10. if (i < B.size()) t += B[i];
  11. C.push_back(t % 10);
  12. t /= 10;
  13. }
  14. if (t) C.push_back(t);
  15. return C;
  16. }

高精度减法

  1. // C = A - B, 满足A >= B, A >= 0, B >= 0
  2. vector<int> sub(vector<int> &A, vector<int> &B)
  3. {
  4. vector<int> C;
  5. for (int i = 0, t = 0; i < A.size(); i ++ )
  6. {
  7. t = A[i] - t;
  8. if (i < B.size()) t -= B[i];
  9. C.push_back((t + 10) % 10);
  10. if (t < 0) t = 1;
  11. else t = 0;
  12. }
  13. while (C.size() > 1 && C.back() == 0) C.pop_back();
  14. return C;
  15. }

高精度乘低精度

  1. // C = A * b, A >= 0, b >= 0
  2. vector<int> mul(vector<int> &A, int b)
  3. {
  4. vector<int> C;
  5. int t = 0;
  6. for (int i = 0; i < A.size() || t; i ++ )
  7. {
  8. if (i < A.size()) t += A[i] * b;
  9. C.push_back(t % 10);
  10. t /= 10;
  11. }
  12. while (C.size() > 1 && C.back() == 0) C.pop_back();
  13. return C;
  14. }

高精度除以低精度

  1. // A / b = C ... r, A >= 0, b > 0
  2. vector<int> div(vector<int> &A, int b, int &r)
  3. {
  4. vector<int> C;
  5. r = 0;
  6. for (int i = A.size() - 1; i >= 0; i -- )
  7. {
  8. r = r * 10 + A[i];
  9. C.push_back(r / b);
  10. r %= b;
  11. }
  12. reverse(C.begin(), C.end());
  13. while (C.size() > 1 && C.back() == 0) C.pop_back();
  14. return C;
  15. }

一维前缀和

S[i] = a[1] + a[2] + ... a[i]
a[l] + ... + a[r] = S[r] - S[l - 1]

二维前缀和

S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]

一维差分

给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c

二维差分

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c

位运算

求n的第k位数字: n >> k & 1
返回n的最后一位1:lowbit(n) = n & -n

双指针算法

  1. for (int i = 0, j = 0; i < n; i ++ )
  2. {
  3. while (j < i && check(i, j)) j ++ ;
  4. // 具体问题的逻辑
  5. }
  6. 常见问题分类:
  7. (1) 对于一个序列,用两个指针维护一段区间
  8. (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

离散化

  1. vector<int> alls; // 存储所有待离散化的值
  2. sort(alls.begin(), alls.end()); // 将所有值排序
  3. alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素
  4. // 二分求出x对应的离散化的值
  5. int find(int x) // 找到第一个大于等于x的位置
  6. {
  7. int l = 0, r = alls.size() - 1;
  8. while (l < r)
  9. {
  10. int mid = l + r >> 1;
  11. if (alls[mid] >= x) r = mid;
  12. else l = mid + 1;
  13. }
  14. return r + 1; // 映射到1, 2, ...n
  15. }

区间合并

  1. // 将所有存在交集的区间合并
  2. void merge(vector<PII> &segs)
  3. {
  4. vector<PII> res;
  5. sort(segs.begin(), segs.end());
  6. int st = -2e9, ed = -2e9;
  7. for (auto seg : segs)
  8. if (ed < seg.first)
  9. {
  10. if (st != -2e9) res.push_back({st, ed});
  11. st = seg.first, ed = seg.second;
  12. }
  13. else ed = max(ed, seg.second);
  14. if (st != -2e9) res.push_back({st, ed});
  15. segs = res;
  16. }