方法论:万物皆朴素的第一性原理
几乎任何领域的任何问题的解决方案,都可以看作是“某个结构上的朴素方法的优化“。
计算机只能处理规模有限的问题,在给定规模且不考虑效率的情况下,问题一定存在朴素解法。具体手段有直接模拟 / 利用bit枚举 / 各种搜索算法等。
具体方法:从问题到解决方案
一般的问题我们有一般的思考方式,而特殊的问题经过总结可以形成特定的解决方案,供今后调用。这需要长时间的积累。
举出一些算法竞赛中常用的问题——解决方案的思路:
若问题具备 ”线性多维逆序“ 结构,则考虑 CDQ分治。
若问题具备 ”元素唯一归属于某集合“ 结构,则考虑并查集。
若问题具备 ”连通性“ 结构,则考虑搜索 / 并查集。
若问题具备 ”记录数据未来使用“,则考虑哈希表。
若问题具备 “FILO / 可规约” 结构,则考虑栈。
若问题具备 ”线性结构上地最远/近最大/小元素“ 结构,则考虑单调栈。
若问题具备 ”FIFO“ 结构,考虑队列。
若问题具备 ”动态维护滑动窗口“ 结构,考虑单调队列。
若问题具备 ”字符串” 结构,则考虑如下做法:
- 若问题具备 ”字符串匹配“ 结构,则考虑如下做法:
- 若为线性结构,考虑KMP
- 若为Trie结构,考虑AC自动机
- 若问题具备 ”求最长回文子串” 结构,则考虑Mancher算法。
- 若问题具备 ”字符串匹配“ 结构,则考虑如下做法:
若问题具备 “某节点只有一个父节点” 结构,考虑树结构的如下做法:
- 若问题具备 “树的重心/直径/中心/最近公共祖先” 结构,则按经典算法处理。
- 若问题具备 “子树的相同问题” 结构,则考虑递归。
- 若问题具备 “子树的相似问题” 结构,则考虑树形Dp。
- 若问题具备 “对树的操作在区间上简单” 结构,则考虑 树链剖分 + 区间维护
若问题具备 “序无关 / 要求某种序” 结构,则考虑排序。
若问题具备 “求解难, 但是验证解是否可行容易” 结构,则考虑二分答案。
若问题具备 “最大最小 or 最小最大 or 结果单调性/二分性” 结构,则考虑二分。
若问题具备 “枚举单调性” 结构,则考虑双指针。
若问题具备 “大数计算”,则考虑高精度。
若问题具备 “数据范围大但涉及范围小”,则考虑离散化。
若问题具备 “子问题” 结构,则考虑动态规划。
- 若问题具备 ”从1到n符合某些数位限制的个数”,则考虑数位DP
- 若动态规划问题具备 “棋盘上联通约束” 结构,则考虑状态压缩dp
- 若动态规划问题具备 ”固定长度区间最值“ 结构,则考虑单调队列优化。
- 若动态规划问题具备 ”“ 结构,则考虑斜率优化。
- 若动态规划问题具备 ”“ 结构,则考虑四边形不等式优化。
若问题具备 “解空间无限 / 有明显优秀策略“ 结构,考虑贪心。
若问题具备 “分块” 结构,则考虑 分块 / 块状链表 / 莫队优化暴力
若问题具备 ”区间性质“ 结构,则考虑以下经典做法:
- 特殊地,若该性质是区间 ”选点/分组/覆盖/最大不相交“ 的区间数,则按经典问题处理。
- 否则,若该性质具备 ”区间减法 / 区间消去“ 结构,则考虑前缀和 / 差分 / 树状数组 / 线段树 / 平衡树 / 分块。
- 否则,若该性质具备 ”区间加法 / 区间合并“ 结构,则考虑线段树 / 平衡树
若问题具备 “状态迁移最少次数” 结构,则考虑最短路算法。
若问题具备 “” 结构,则考虑最小生成树算法。
若问题具备 “把图分成两部分” 结构,则考虑二分图算法。
若问题具备 “把图变成拓扑图” 结构,则考虑强连通分量算法。
若问题具备 “对拓扑图求拓扑序” 结构,则考虑拓扑排序算法。
若问题具备 “对图恰好走一遍” 结构,则考虑欧拉路径和回路算法。
若问题具备 “差分约束” 结构,则考虑图的差分约束算法。
若问题具备 “判环” 结构,则考虑SPFA判环。
若问题具备 ”面积并”,则考虑计算几何面积并。
若问题具备 “最大公约数和最小公倍数“,则考虑gcd。
若问题具备 “进制相关“ 结构,则考虑进制转换。
若问题具备 “质数相关“ 结构,则考虑判定质数/分解质因数/质数筛
若问题具备 ”约数相关” 结构,则考虑所有约数/求约数个数/求约束之和
若问题具备 “欧拉函数相关” 结构,考虑欧拉函数算法
若问题具备 “幂相关” 结构,考虑快速幂
若问题具备 “”溢出long long但是时间限制不严格“ 结构,考虑龟速乘
若问题具备 “矩阵运算相关“ 结构,考虑矩阵计算/矩阵快速幂
若问题具备 ”阶乘计算相关“ 结构,考虑阶乘快速计算
若问题具备 ”线性同余方程“ 结构,考虑扩展欧几里得
若问题具备 “线性方程组相关” 结构,考虑高斯消元
若问题具备 “组合数”,考虑求组合数的四种算法
若问题具备 “容斥” 结构,考虑容斥计算
若问题具备 “博弈论” 结构,考虑博弈论
当然这只是冰山一角,真正的细节还有很多。熟练的Coding是刻意练习的结果。
()