ybtoj题型整理
全心全意 品质为真
常用技巧
构造
1.通过一些构造,将原问题转化为更易于解决的问题.
- 将一个与答案有关的二维组转化为0/1矩阵.
对应题目
2.对于特殊的状态或操作,我们可以设立一个虚拟点.
3.在遇到一些新定义问题时,我们可以考察关系\(P\)是否具有传递性,若具有,我们可以通过分别构造满足某约束的唯一对象\(C,D\),使得\(A\)与\(C\),\(B\)与\(D\)有关系\(P\),这样,当且仅当\(C=D\)时,\(A\)与\(B\)有关系\(P\).
对应题目
位运算
1.对于一些与二进制位有关的问题,我们可以依次的考虑每一位.
2.我们发现异或有性质\(x \oplus x = 0\),因此设树的根节点为\(r\),可以将链\(i,r\)与链\(r,j\)合并,得到链\(i,j\),而不需要考虑\(lca(i,j)\)是谁.
对应题目
3.对于两个数\(i,j\),如果\(i\)和\(j\)的前\(k\)位都相同(由高到低),第\(k+1\)位不同,不难发现如果一个整数\(m\)的第\(k+1\)位与\(i\)一致,则有\(i \oplus m < j \oplus m\).因此,若\(i \neq j\),则有\(2^{M-1}\)个整数\(m\)使得\(i \oplus m < j \oplus m\).
对应题目
4.若定义\(f(x)=x \& 2^n\),我们发现该函数是有周期性的.
对应题目
数学
1.\(k\)个集合\(A_i\)的交集为空集的充要条件是:对于任一元素\(i\in U\),\(i\)不会同时出现在所有\(A_i\)中.
对应题目
对应题目
对应题目
4.对于一个二元方程,可以考虑用一个未知数表示另一个.
对应题目
5.如果数学公式的分母是一个一次的二项式,可以考虑换元处理.
对应题目
6.余数可以做如下变形:
对应题目
7.如果有一个整数\(k\),需求一个数列\(a_n=\lfloor \frac{k}{n} \rfloor\),可以使用数论分块的方式,时间复杂度\(O(\sqrt{n})\).
对应题目
8.\(m!\)中\(2\)的质因子数量为\(\sum_{i=1}^{2^i\leqslant m}\lfloor \frac{m}{2^i}\rfloor\).
对应题目
对应题目
10.对于区间的平均值问题,我们发现考察是否存在一个区间\([l,r]\),使得
是较为困难的,但我们发现原式等价于
这个问题是比较简单的,只需要新数列中有一个区间元素和非负即可.
对应题目
数据结构
1.现有一个序列\(a_i\),对任意元素\(a_i\),记小于\(a_i\)的极大元素为\(a_j(j<i)\),我们需要求解上一个出现的\(a_j\)距\(a_i\)的距离.对于这个问题,我们采用双向链表法,每个元素都是一个栈,栈中每个元素\(i\)对应的\(a_i\)就是栈的序号.我们先将所有\(a_i\)都压入对应栈中,然后从右向左处理每个\(i\),找到链表中\(a_i\)的上一个元素,即对应的\(a_j\),随后将\(i\)出栈,若该栈已经为空,则将该栈在链表中删掉.
对应题目
2.单调栈可以解决在序列\(a_i\)中,对任一位置\(i\),求最小的\(j\),使得\(j > i\)且\(a_j < a_i\)的问题.
对应题目
3.霍夫曼树:现有一些节点,每个节点有权值\(w_i\),要求构造一个\(k\)叉树,每个节点的深度为\(dep_i\),使得\(\sum{w_i*dep_i}\)最小.
对应题目
树论
1.如果需要求解一棵树上满足某性质的一条链\(i,j\),我们可以考虑对每个\(u\),枚举两个\(u\)子树上的点\(i,j\),通过递推的某种性质将链\(i,u\)与链\(u,j\)合并,得到链\(i,j\),并计入答案.
对应题目
2.在dfs序的角度上,树上的每个节点都管辖着一段区间.在如果该树满足二叉搜索树的性质,则可以认为一个点的子孙节点都在该区间内.
3.我们有一些链\((u_i,v_i)\),求解对于每个点\(i\),经过该点的链的个数.这个问题可以树上差分解决.
对应题目
对应题目
图论
1.如果边和点均具有权值,如果我们发现每个点的经过次数恰好等于与其相连的边数,那么不妨在计算边的权值时,直接计算边权与两端点权之和.
对应题目
2.我们可以通过数学推导,自己定义一条边的代价值.
对应题目
3.对于一些每个状态带有一个附加属性(且属性值域不大)的题目,考虑用分层图.
4.对于一些不等式组,我们将它转化为同一形式\(a_i \geqslant a_j + d\),用\(d\)代表边权,跑差分约束.
基本思想
1.对原问题做一些简单数学变形来简化问题,或企图寻找最优解的性质.
对应题目
2.我们通过一些手动模拟/打表的方式,来获得一些特殊性质,从而解决问题;对一些规则依赖严格,不少位置有唯一解的方案统计题,不妨手动模拟一些情况,找规律,得出数学公式.
3.当我们发现问题含有多个未知数,难以同时考虑时,在时间允许的情况下,我们可以考虑将其中一个未知量枚举处理.或者在有单调性时,二分处理.
4.对于一些情况复杂的题,我们可以考虑将复杂情况转化为较简单情况.
对应题目
贡献计算
1.计算贡献时,可以考虑每种结果有多少种方案数,再相加.
2.考虑每个元素对答案固定不变的贡献,再分离的考虑有关于具体方案的贡献.
对应题目
3.我们通过一些数学变形,考虑树上每个节点对答案的贡献/维护每个节点的一些性质,直接得出答案.
4.对于一些答案贡献来源复杂的题,我们可以分别讨论每一种贡献来源,用不同方式解决.
对应题目
区间问题
1.对于一些考察区间内有无含有特殊性质的元素的问题,我们可以通过记录上一个有特殊性质的位置来实现\(O(1)\)的查询.
对应题目
2.对于一个集合\(A\),其中每个元素都是一个整数集的有限子集,我们需要找到一个最短区间\([l,r]\),使得对任意\(M\in A\),总存在一个\(k\in M\),使得\(k \in [l,r]\).这个问题我们考虑尺取法(本质双指针),记录当前每个集合\(M_i\)中我们已包含的元素个数\(cnt_i\),我们每次将右指针拓展,如果左指针处元素不属于任一集合\(M\),或对任意集合\(M_i \ni l\),都有\(cnt_i > 1\),则左指针可以收缩,并计入答案.
对应题目
3.我们在处理一些区间问题时,不妨将原区间转化为左闭右开区间,这样会便于合并/分类...
对应题目
差分与前缀和
1.在计算\(\displaystyle\sum_{i,j}a_ia_j\) 时,我们可以使用前缀和技巧,将复杂度降至\(O(n)\).
对应题目
2.我们在处理区间问题时,可以通过前缀和等技巧转为单点问题.
3.使用差分技巧来解决区间等差数列加问题.
对应题目
杂项
1.我们从\(x\)个数中可重复选出两个,方案数为\(x^2\),因此涉及到\(x^2\)的题可以考虑从计算数对个数的角度计算贡献.
对应题目
2.处理较高维的问题时,可以先处理低维问题,在考虑如何向高维转移.
对应题目
3.遇到可以将前后连为一个环(在模意义下)的题目时,可以考虑复制一份,按链处理.
第一章 基础算法
递推问题
1.我们一般考虑将含有\(i\)个元素的问题的答案,由\(f(i)\)(其中\(f(i) < i\))的问题答案来推出.
2.当我们发现我们设计的状态难以转移(或是无法满足无后效性)时,我们考虑升维(时空足够).
3.对于一些数的划分问题,为保证答案不重复,我们采取非降原则.
对应题目
4.我们考虑在模拟解决一个问题的过程中,是否有一个特殊的时间戳,将其转化为多个形式相近的子问题.
对应题目
5.当每种方案较为复杂,但遵循一定规律时,我们考虑将每一种方案用一些特殊属性唯一表示出来.或者说,当状态难以转移时,我们给状态的定义附加一些特殊性质.
贪心算法
1.用你的人类智慧去猜测一些最优方案,并尝试证明.
2.经典题型:线段覆盖
二分问题
1.考虑二分答案,考虑如何对答案加以验证.我们考察大于答案的部分有什么异于小于部分的特殊性质.
对应题目
2.用dp的方式去验证答案.
对应题目
3.二分结合Hash来解决一些字符串极大匹配长度/极大回文长度的问题.
深度优先搜索
1.依次对每个元素做出决策,递归搜索,随后回溯.
2.我们利用一些对答案的限制:可行性剪枝/最优性剪枝,在可接受的复杂度内对已做出的决策进行检验,从而剪枝.
3.在剪枝仍不够优秀的情况下,我们可以探究已做出决策的量在数学上有何放缩不等关系,从而剪枝.
对应题目
4.当发现\(O(2^n)\)的复杂度无法接受,但\(n\)依然小到不爆搜令人惋惜的地步时,我们可以考虑将原序列分为两段,在\(O(2^{\frac{n}{2}})\)的时间内处理两段的结果,再将结果合并.
对应题目
5.在面对类似背包问题,但值域巨大无法接受时,我们可以考察物品个数,尝试爆搜解决问题.
对应题目
6.我们可以结合贪心,找到最优策略后进行搜索.
对应题目
7.我们考察决策的对称性,尝试在保证正确性的条件下只做对称轴一侧的决策,从而将\(O(2^n)\)或\(O(n!)\)的复杂度降至\(O(2^{\frac{n}{2}})\)或\(O(\frac{n}{2}!)\).
对应题目
广度搜索
1.我们通过一些属性来定义状态,这些属性应该做到:明确下一步的状态,明确何时结束,(时空标程允许).由于bfs的天性,我们可以轻松计算出最小的操作次数/是否连通.
一些可能的维度:
- 对象的坐标\(x_i,y_i\)
- 某些技能的使用次数\(d_i\)
2.我们可以通过广搜来完成一些将一个矩阵分为一些连通块并计数/计算每个块属性的任务.
3.在一些边权只有0/1的图上,我们可以进行0/1bfs.
对应题目
4.有些时候,目标状态并不止一个,我们根据题意预处理目标状态有哪些.
对应题目
5.当目标状态也在移动时,我们可以在每次bfs完一个时间戳后模拟目标的移动.
对应题目
6.当我们需要前k优的方案时,我们可以类似bfs的方式,由最优解一步步退化,并入堆.
对应题目
第二章 字符串算法
字符串处理
1.字符串基本操作:
basic_string( const basic_string& other,size_type pos, size_type count);
size_type size() const;
size_type find( const basic_string& str, size_type pos = 0 ) const noexcept;
Hash与Hash表
1.通过计算某对象的Hash值,我们将一个对象转为一个整数,并通过研究其Hash值来探究原对象是否相等.
2.我们可以使用map
/set
/哈希表(unordered_map
)来解决一些去重/查询问题.其中前者时间复杂度约为对数级,但元素有序;后者均摊常数复杂度,但元素无序.
3.二分结合Hash来解决一些字符串极大匹配长度/极大回文长度的问题.
KMP算法
1.我们可以通过KMP算法来求出模式串中匹配串的个数.
2.kmp也可以求解周期.
对应题目
3.当我们对某个位置的周期/border的某个属性(如最小/超过某值的最小)很感兴趣时,我们可以另开辟一个数组,并在满足其最小条件后,转移时只摆烂,不拓展.
4.发现\(nxt\)数组其实是一个树状结构,可以在其上做一些dp任务.
对应题目
5.我们可以通过\(nxt\)的定义,由\(nxt\)数组反推回字典序最小的原字符串.
对应题目
6.当涉及到只关心形式,而不关心具体字母的匹配时(如认为"abdbd"与"ghjhj"是匹配的),我们可以用元素与该元素上次出现的距离做匹配.
- 类似的,如果我们只关心元素在子串中的字典序,我们可以匹配元素到上一个比它大的最小元素距离,到上一个比它小的最大元素距离,到上一个与它相等元素距离.
Trie树
1.通过Trie树来统计对于一个给定串\(S\),在字典树中有多少串\(T\)满足\(S\)是\(T\)的前缀/是否存在一个\(T\),使\(T=S\).
2.我们通过将一个数用二进制的方式表示,看做一个字符串插入字典树,来解决有关于异或的问题.
AC自动机
1.AC自动机可以在一个匹配串中同时匹配多个文本串.由于其拓扑排序的步骤,AC自动机可以在fail树上dp.
2.在AC自动机上可以对每个节点进行dp,自动机状态转移边即为dp的转移,由于自动机显然有环,dp的一个状态必然是dp轮数.
第三章 图论
并查集
1.并查集是用来维护将一些元素合并为一些类别的数据结构.同时代表元素也可以存储一些有关该连通块的属性(如大小).
2.带权并查集可以用来维护一些合并元素,并且可维护每个元素与代表元素关系的数据结构,并且该关系可以通过更新前权值和旧代表元素权值推出.
3.并查集可以处理一些序列问题,我们设一个元素的代表元素代表该元素的下一个(包含该元素)可用元素,如果某元素在用过后就不可以再使用,我们就把它和它的前一个/后一个元素合并.
最小生成树
1.通过kruskal生成最小生成树.
2.我们可以通过最小生成树来贪心解决一些问题.
对应题目
3.我们可以通过对最小生成树的某条边进行松弛,得到次小生成树.
对应题目
最短路径
1.可通过dijkstra的方式,求单源最短路(无负边).
2.用spfa算法来判负环,求解含负边权的最短路.
3.不一定最短路就是边权和,可能是某个属性.
4.通过floyd去解决图上任意两点\(u,v\)间的最短路.
对应题目
强连通分量
1.tarjan可用于将一个强连通分量缩成一个点,随后在DAG上做dp.
第四章 数据结构
堆的应用
1.堆可以动态维护一个集合中的最值.
2.堆可以用来维护前k大/前k小.
对应题目
3.堆可以维护最值,从而支持一些贪心的决策.
树状数组
1.树状数组可以用来实现一些区间查改,单点查改的操作.
2.树状数组可以支持动态区间求和,从而优化dp.
对应题目
3.特别地,(权值)树状数组可以求逆序对.
4.权值树状数组可以通过初始全1,一个个-1的方式来维护区间内有效元素个数.
对应题目
RMQ问题
1.st表可以离线查询区间最值.
2.st表可以支持运算\(\bigoplus\),当且仅当\(x \bigoplus x = x\).
对应题目
线段树
1.线段树可以维护区间和/积.
2.线段树可以模拟一些操作.
3.线段树可以维护最长前缀/最长后缀,从而解决某区间的一个有特殊性质的子区间问题.
对应题目
4.线段树可以维护一个区间内某个元素的数量,实现桶排序.
对应题目
5.当我们发现对某一元素的操作次数是极其有限的时,我们只需暴力进行操作,与此同时记录区间内已经操作到底的元素个数.
对应题目
LCA问题
1.我们可以通过求解lca来判断两节点是否有祖先关系.
对应题目
2.树上一条链的长度可以分解为两端节点到lca的距离和.
倍增问题
1.若我们可以进行多次操作,但是操作到一定程度不能再操作,并且可以判断是否操作过度时,可以使用倍增处理.
2.如果我们对是否可以由\(u\)经\(2^k\)条边到达\(v\),我们可以设计状态由\(u\)是否能经\(2^i\)条边到达\(v\)为\(f_{u,v,i}\),可以通过类似floyd的方式转移.
对应题目
3.通过在对数级时间内获得信息来优化dp时间复杂度.
对应题目
第五章 动态规划
背包问题
1.普通背包
对应题目
2.完全背包
对应题目
3.多重背包
4.树上背包
5.混合背包
对应题目
6.可以在每个物品上消耗多份代价.
对应题目
7.如果有多种代价,可以将dp数组升维.
对应题目
区间dp
1.区间dp可以考虑某个区间内的元素所得到的答案.
2.较为复杂的考虑状态转移--最高宗旨就是只要让区间长度变小就好,哪怕只有一格.
对应题目
3.也可以设计状态为某区间在一定特殊性质下的答案.
对应题目
4.如果有类似"删去相邻两个物品,使得它左右相邻"的表述,则可以从枚举断点和区间左右端点可以相邻两个角度转移.
对应题目
5.如果有类似"删去一个物品,使两侧相邻"的表述,且操作贡献与两侧相关,我们发现计算\([i,r]\)转移方式可以是先删掉\([i,k]\),再删\([k+2,r]\),再删\(k+1\),这样的话删\(k+1\)时的左右两侧就是\(l-1,r+1\).这样的话每个\(f\)的值都是建立在\([l,r]\)的左右元素都未被删除的条件下,且转移成立.
对应题目
6.如果操作的代价与最大/最小值有关,且涉及到类似"删去相邻一段物品,使得它左右相邻"的表述,我们也可以先将子区间删掉,再删掉值域在一定范围内的物品.注意检查转移的全面性,不仅要及时计算\([l,r]\)内删掉值域不在\([mn,mx]\)的物品的代价,还要计算\([l,r]\)内物品删光的代价.
对应题目
数位dp
1.数位dp主要思考前面填的位置的什么属性对答案是有影响的.记搜即可.下面是一些常记录的属性.
- 是否出现某(些)数字 \(\rightarrow\) 状压记录是否出现过每个数字
对应题目
- 是否被某些数\(a_1,a_2,a_3...\)整除 \(\rightarrow\) 记录已经填的数对\(lcm(a_1,a_2,a_3,...)\)的余数.
对应题目
- 是否出现某数字串 \(\rightarrow\) 记录填的数的后缀与目标串匹配长度(或者已经填的数中已经包含目标串).
- 某些数出现次数 \(\rightarrow\) 每个数出现的次数(此时需要考虑前缀0)
2.如果被卡常了,可以循环预处理出dp表,然后接着搜.
对应题目
树形dp
1.记录每个节点被覆盖的状态.
2.如果父节点的状态可能由子节点转移,子节点可能不能重复转移时,可以额外记录次优解.
对应题目
3.从根结点出发,要求经过树上所有点,求最短长度,就是用总边权2倍减掉最长链长度.
4.记录子树的大小.
对应题目
5.我们可以由底到顶进行一次dp,再从顶到底计算更有普遍性的问题答案,再进行一次dp.
单调队列
1.有数列\(a_i\),对于每一个\(l\),单调队列可求\(max\{a_{l...l+len}\}\).
对应题目
2.我们可以利用单调队列的功能优化dp.
3.不一定\(dp_i\)范围就是\(dp_{i-k...i-1}\),可以手动模拟每次滑动窗口的位置.
4.有时转移范围(或者说区间长度)并不是固定的,要预先求出范围,再双指针跑单调队列.
第六章 数学基础
矩阵快速幂
1.矩阵快速幂可用于一些线性递推问题.具体的,若有序列\(a_i\),其递推公式为
则可以发现性质:
因此可以实现快速幂优化.
2.普通的快速幂可以实现\(a^n\)的快速求解.
3.类似于矩阵相乘的操作,只要满足交换律,结合律,都可以使用矩阵快速幂.(尤其是类似有限步floyd)的操作.
4.给定一个\(n\times n\)矩阵\(A\),以及一常数\(k\),要求求出矩阵\(B=A+A^2+...+A^k\).
我们构造一个矩阵
这样,不难发现,该矩阵有如下性质:
根据数学归纳法,不难得到:
对应题目
质数和约数
1.欧拉筛可以在线性时间内筛出质数.
对应题目
2.当查询区间较小时,可以考虑先求出\([1,\sqrt{r}]\)内的素数,再对每一个素数进行查询区间内的埃氏筛.
对应题目
3.将一个数质因数分解可以直接暴力枚举,时间复杂度\(O(\sqrt{n})\).
4.哥德巴赫猜想:对任意一个偶数\(k > 2\),都可以将其分解为两个质数的和.
对应题目
5.有一个数列\(a_n\),现要求找出一个数对\((i,j)\),使得\(\gcd(i,j)\)最大.我们可以对每个元素都枚举因数,在找到最大的记录过两次的数,时间复杂度\(O(n\sqrt n)\).
对应题目
6.我们将一个整数\(d\)表示为\(\prod_{i=1}^n{p_i}^{k_i}\)的形式,则\(d\)的约数个数为\(\prod_{i=1}^n(k_i+1)\).
7.我们将一个整数\(d\)表示为\(\prod_{i=1}^n{p_i}^{k_i}\)的形式,则\(d\)的约数之和为\(\prod_{i=1}^n\sum_{j=0}^{k_i-1}p_i^j\).
对应题目
同余问题
1.exgcd可以求解\(ax+by=m \)的解,进一步的,这就等价于求解\(ax \equiv m \mod b\),特别地,也可以求解逆元.
2.线性求逆元:我们设\(p=kx+r\),则有:
因此,我们可以通过\(r\)的逆元推得\(x\)的逆元,实现线性求区间\([1,m]\)模\(p\)意义下的逆元.
对应题目
3.中国剩余定理可以求解线性齐次同余方程组,更一般地,exCRT可以处理\(p_i,p_j\)不互质的情况.
4.在值域不大时,如果我们需要求解一些乘法除法后变量对\(p\)取模的结果,但\(p\)不是质数,我们可以将操作数质因数分解,与\(p\)共有的部分记录指数,查询时快速幂处理,与\(p\)互质的部分直接乘或乘逆元.
对应题目
5.如果想求解一个数对合数取模的结果,可以先将合数分解,再使用CRT合并.
对应题目
6.如果需要求解\(a^n \mod P\),但\(n\)极大,我们有
对应题目
7.对任意质数\(P\),\(\phi(P) = P - 1\).
对应题目
组合数学
1.对于任意\(i\in[1,n]\)以及一常数\(n\),可以用\(C_n^i=\frac{n-i+1}{i}C_n^{i-1}\)的方式递推,时间复杂度\(O(n)\).
对应题目
2.组合数有性质:\(C_n^i=C_n^{n-i}\).
对应题目
3.组合数有性质:\(\sum_{i=0}^nC_n^i=2^n\).
对应题目
4.对任意\(i,j\in[1,n]\),我们可以用\(C_i^j=C_{i-1}^j+C_{i-1}^{j-1}\)来递推,时间复杂度\(O(n^2)\)
5.当模数不大时,我么可以用卢卡斯定理求解组合数:
6.如果想要使用卢卡斯定理,但是模数是一个合数,可以使用exLucas定理.
对应题目
7.面对将元素分为一定数量组的题目时,可以使用隔板法.
8.在棋盘格上选择一些不在同一行,不在同一列上的点,可以先考虑在哪几行上,再考虑在哪几列上,最后考虑将这些行和列做全排列匹配.
对应题目
9.可以考虑使用容斥原理进行计数.
对应题目
10.可以将组合数转化为阶乘,在进行数学变形.
对应题目
11.常见的组合数:卡特兰数.
对应题目
博弈论
1.NIM游戏的先手必败,当且仅当\(a_i\)的异或和为0.
对应题目
2.对于一个有向图游戏组合,先手必败,当且仅当\(sg_i\)的异或和为0.要计算\(sg\)值,只需将所有可能的转移情况记录下来,取第一个未被记录的.若转移结果是一个有向图游戏组合,只需求异或和在记录即可.
3.若题目中的游戏只规定何为胜,我们需要先将其转化为败的边界.
对应题目
4.也可以通过寻找规律来考察何时先手必败.
5.阶梯NIM:将第\(i\)个位置的\(m\)个箱子转移到\(i-1\)处,无法操作者败.该问题只与奇数层/位置的箱子数有关,做奇数位置的异或和即可.
对应题目
期望问题
1.依次计算每项的期望,再相加.
对应题目
2.考察添加一项对答案有什么增加量.
对应题目
3.如果一个状态的到达方式不唯一,不妨倒着考虑问题.
对应题目
3.概率dp时,可考虑已求得的dp值的实际意义来设计转移.