题面转化 tricks
从复杂度入手
以下展示了一些经典的算法的复杂度。当然还有很多遗漏的,接下来慢慢补。
| 数据规模(以1000ms时限为例) | 典型的对应算法 | 复杂度 |
|---|---|---|
| \(1\le n\le 10\) | 全排列 | \(O(n!)\) |
| \(1\le n\le C\times 20\) | 搜索;状态压缩 | \(O(2^n)\)(注意常数对复杂度带来的毁灭性影响) |
| \(1\le n\le 100\) | Floyd;矩阵乘法 | \(O(n^3)\) |
| \(1\le n\le 10^3\) | 很多,写不下 | \(O(n^2)\) |
| \(1\le n\le 5\times 10^5\) | 分块;莫队;根号分治;均摊(如BSGS) | \(O(n\sqrt{n})\) |
| \(1\le n\le C\times 10^6\) | 线段树(常数很大);树状数组;分治;倍增预处理; \(n\) 次 \(O(\log n\)) 操作 | \(O(n\log n)\) |
| \(1\le n\le C\times 10^6/10^7\) | 欧拉筛;\(n\) 次 \(O(1)\) 操作 | \(O(n)/O(n\log\log n)\) |
| \(1\le n\le 10^{12}\) | 质因数分解;整除分块 | \(O(\sqrt{n})\) |
| \(1\le n\le 10^{18}\) 或者更大(高精度) | 快速幂;线段树、树状数组、倍增lca等的修改、查询操作;log函数;set/map等stl;vector(均摊);优化并查集 | \(O(\log n)/O(\log\log n)\) |
| \(1\le n\le 10^{18}\) 或者更大(高精度) | st表查询;预处理如前缀和和差分;单调栈、单调队列;双优化并查集 | \(O(1)/O(\alpha(n))\)(反阿克曼函数) |
“抽象”操作转化
如果你遇到了一个陌生和古怪的操作,然后又让你快速计算某种结果或是计数,可以考虑找到一个在操作中不变的量,或是与操作等价的弱化版问题,从这个量出发思考问题。
这实际上就是区间数颜色等问题的背后逻辑。在此列举出一些冷门的转化。
\(a\in\{1,2,3\}\) 消除相邻两个不同数 变成 没出现的另一个
区间异或和不变,而且异或和代表了最终得到的字母。
神秘数
一个可重集合的 神秘数 定义为将该集合中若干个数字相加无法得到的最小正整数。
找到第一个 \(k\) 满足 \(\sum\limits_{i=1}^k a_i < a_{i+1}-1\),那么神秘数就是 \((\sum\limits_{i=1}^k a_i )+1\)。证明使用数学归纳法易证。
建图
查询区间异或和
众所周知,同一个数异或两次会抵消。定义 \(f(a,b)\) 表示查询区间 \([a,b]\) 的异或和。那么有 \(f(a_1,a_2)\bigoplus f(a_2,a_3)\bigoplus ...\bigoplus f(a_{n-1},a_n)=f(a_1,a_n)\) 。注意这里规定 \(f(a,b)=f(b,a)\) ,不限制 \(a\le b\) 。
把 \(f(a,b)\) 当成从 \(a\) 到 \(b\) 的边,那么这有点像图论中的连通性问题。
运用:给定长度为 \(n\) 的 \(0/1\) 序列,你可以花费 \(f_{i,j}\) 代价查询区间 \([i,j]\) 的异或和,求得知序列所有位置答案的最小代价。
解法:容易发现,这是一个连通性问题,你的目的是使所有 \(n+1\) 个数字间的“缝隙”联通。最小生成树可以完成这个问题。
最小值DP转为最短路
如果要求某个些状态的最小值,由不方便转移,可以考虑记忆化搜索把转化为节点,把转移方式转化为有向边,跑最短路算法。当然你不必把所有边都建出来,只有要用的时候算一下就行。
容斥原理
正难则反
本题如果直接统计纯黑色三元组和纯白色三元组会很复杂。考虑统计杂色三元组。一个杂色三元组的边构成是 黑黑白 或者 黑白白。考虑对于每个点统计与之相连的 \(黑边数\times白边数\) 加和,得到了答案的两倍(因为一个杂色环一定具有2个杂色角)。
转化二分
如果问题中值域只有 \(0\) 和 \(1\) 会更好做,并且求的是序列中某个位置/某种操作下得到的单个数,且操作与实际值无关只与大小有关,那么可以二分答案,把 \(\le mid\) 的标为 \(0\),\(\ge mid\) 的标为 \(1\)。
中位数最值
如果要求某些条件下中位数的最值,可以二分答案。把 \(< mid\) 的当作 \(-1\),\(>mid\) 的当作 \(1\),这样只需求出是否有合法的和 \(\ge 0\) 的即可。
其他经典的tricks
可差分量的区间查询/修改(不能既查又修)
直接差分,转化为两点的问题,使用 并查集/图论/最小生成树 之类算法解决。
区间内不同颜色
每个位置维护一个 \(pre_i\) 表示上一次相同的元素。如果 \(pre_i<l\) 说明区间 \([l,r]\) 中没有与 \(a_i\) 重复的元素。其他的运用同理。这是非常常见的trick,一般用线段树等数据结构维护。
mex
一个集合 \(S\) 的mex是指最小的不属于 \(S\) 的非负整数。
mex具备一个有趣的性质:如果集合不包含0,那么它的mex就是0
只能在mex(S)没被删除时删除集合S
如果要删除0,那么0一定是最后删除,因为删除了0之后,别的要删的时候就没有mex了,也就删不了了。
区间查询mex
我以为很简单,但是貌似有难度,要用带修莫队+值域分块:CF940F
破环为链
常见于区间DP、线性DP。将环复制两份,当作链处理即可。注意不能允许把同一个元素计算两次的情况。
走路遍历一棵树
每次走一条边,遍历整棵树的需要的次数是 \((点数-1)\times 2-到起点的最远点距离\)。这是因为走到最远点后就不用回到起点了,这些边只被走了一遍。

浙公网安备 33010602011771号