- 解法分类
- “满足要求的最大值”“最大值最小” => 考虑二分
- “字典序最小/最大的结果” => 考虑贪心(因为使当前项更小一定会使结果更优),如 CF1547D Co-growing Sequence就是一道按位贪心的题目(实际解法可以直接用位运算而不是按位枚举);补充: 如果在某些涉及位运算及相关知识的题目中,可能会出现“最大值”“最小值”等问题,此时也可以考虑从高到低按位贪心(类似于字典序最小),例题:CF1554C Mikasa
- 对点集排序,某些点需满足特定关系 => 考虑拓扑排序
- 遇到DP题,先从简单情况入手(有时就是DP的初始状态)。比如 CF187B AlgoRace,这道题就可以先考虑不换车的情况(Floyd板子),再列转移方程,推广到其他情况
- 遇到判正环或者求最长路,将所有的边权取相反数,例题:P1938 [USACO09NOV]Job Hunt S
- 没有思路先暴力,考虑去除冗余情况有时也是一种解法
- 求区间$(l, r)$的个数或找所有满足要求的区间 => 有时可以考虑双指针(尺取法)
- 当整体问题不便于解决时,可以考虑每个“个体”对整体的贡献,例1:CF547B Mike and Feet,此题中则可以考虑每个值可以作为那些区间的最小值(单调栈解决);例2:P2422 良好的感觉,此题中则可考虑每一天为最不舒服的那一天时,区间的感受值最大为多少(区间尽量大,仍然是单调栈解决)
- 若区间左端点 $\in [l, mid]$,区间右端点 $\in [mid, r]$(即 $mid$ 一定在区间中),则最大区间和等于 $\max_{i=mid}^{r}sum_i - \min_{i=l-1}^{mid-1}sum_i$,其中 $sum_i$ 表示前缀和
- 对于修改+查询类题目,若有两种解法,一种修改 $O(n)$、查询 $O(1)$,一种修改 $O(1)$、查询 $O(n)$,那么可以考虑利用分块进行折中;典型的分块优化方式为分成两层处理:修改/查询时 $O(\sqrt{n})$ 处理整块部分(块层次),再 $O(\sqrt{n})$ 处理区间两端的零碎部分(个体层次);例题:
- “区间 $[l, r]$ 内小于等于 $k$ 的元素的个数”
- 静态:区间排序+二分(
lower_bound()
/ upper_bound()
),例:[太戈 1058] 进攻长城,代码 - 动态:树状数组维护,例:[太戈 1058] 进攻长城,代码
- 当添加元素 $a[i]$ 时,
add(a[i], 1)
- 对 $1$ 至 $l - 1$ 号元素
add(a[i], 1)
,此时 query(k)
就是区间 $[1, l - 1]$ 中小于等于 $k$ 的元素个数 - 继续对 $l$ 至 $r$ 号元素
add(a[i], 1)
,此时 query(k)
就是区间 $[1, r]$ 中小于等于 $k$ 的元素个数 - 两者相减
- 树上问题,求两点间的距离(
d[i]
表示 $i$ 节点的深度):d[u] + d[v] - 2 * d[lca(u, v)]
- 树上问题思考策略:
- 线性结构上的问题常用思维方法:一维数组用二维平面点可视化(下标为横坐标,值为纵坐标)