各知识点运用技巧总结
动态规划板块
背包
有负体积的时候可以把数组下标平移一段,01背包压维时,正的倒着跑访问的是上一层的,负的正着跑也访问的是上一层的。
二进制拆包:多重背包问题枚举for(j=1;j<=num;(j<<=1))之后当成01背包倒序枚举V
期望
如果转化为建图模型,对于边(u,v)有的题目是从v->u,这样是由u的后继推u
树形
换根dfs的时候一定要把图画出来,比如对于节点u,其父亲为根的情况已经被处理,那么就以fa为根,画至少3个儿子(包括u),然后u也多画几个儿子,一定要把情况枚举完。
时刻注意状态转移时for循环是正序还是倒序。
边界一定要清楚,把i,j能跑到的地方都看一下有没有意义。
区间
状压
记忆化
线性
数学板块
数论
有的gcd的题目是可以打表找规律的。
有的gcd的题目是可以大概感性证明一下就开始写的。
组合数
递推&矩阵乘法
图论板块
最短路
类似于华容道,要会表达状态,建模过程:表达状态$->$找到状态间的代价$->$建图。
最短路可以记录起点,如找集合V内两两之间最短路的最小值,可以记录起点的颜色,在最短路算法中转移,正反跑两边,把最短路连接起来。
如果从多个起点开始跑,那么dist的意义就是到这些点最短路的最小值。
Floyd判负环:dist[i][i]初始为0,跑完之后<0则有负环。
spfa在队列中保存的更新信息的意义是"这个点被更新过,因而有可能通过与它连接的边更新这些边的其它端点"。直到队列为空,此局面表示"没有一个结点可能更新其它的结点"。
spfa可以转移有后效性的带环的图上DP
模意义最短路dist[i][j]表示起点到i,在%p意义下为j,所用的最小代价。
强连通
tarjan+toposort+dp懂得。
双联通
差分约束
有的题统计个数,可能出现SCC,且每个SCC之间的限制不会影响SCC内部的限制,那么答案就是每个SCC内的最长路+颜色数。
2-SAT
基环树
欧拉回路
网络流
生成树
拓扑排序
LCA
有的题可以转化为LCA问题,类似于跳跳棋的神题。
数据结构板块
并查集
并查集缩边乱搞。
栈和队列(单调栈和单调队列)
单调栈:一般用来找向左向右第一个比当前元素大(小)的值,一般在弹栈的时候更新,许多题目都是在弹栈的时候用栈顶元素的信息更新下面的,或者用栈顶元素的信息更新加入的,从而达到统计的目的,如最大子矩阵,每次弹栈时,如果栈顶大于当前高度,那么比第一个比栈顶小的就是第一个比当前高度小的,我们用栈顶更新当前高度再入栈。还有的题目用单调栈统计信息,总之单调栈的题目基本都是围绕左(右)边第一个比当前元素大(小)的元素,有时还有他们之间的距离在一起搞事。
单调队列:先弹队首,再弹队尾,再入队,(再转移)。
堆(可并堆)
堆的删除:q1为有的元素,q2为要删除的元素,控制q2不为空且q1的堆顶等于q2的堆顶,把q1,q2的堆顶一起弹掉,记得判断q1是否为空
堆可以用来维护可反悔的贪心,一般要推一下式子,考虑如果开始对i进行了处理,并认为它是最优解,那么如果后面j可以同时消除i,j的影响,那么显然此时有更优解,那么就用当前的代价减去之间的最优解,得到中间的差值就相当于反悔了一步,重新选择。
线段树(权值线段树,主席树)
线段树的区间维护能力还是很强的,权值线段树一般用来解决第k大问题,就是线段树二分,线段树可以套很多东西。
套堆维护带删除的区间最值,不需要pushup和pushdown,把元素扔进去自动就更新区间信息了。
套权值线段树维护区间k大值。
还有套路就是开K棵线段树维护区间K元素的信息。
还有一些不同于区间和,区间最值的东西,比如颜色数,最长单调子串,或最长0串等,只考虑把两个区间的信息合并成一个这一步即可。
比如维护最长上升子串,我们可以维护从l开始的子串长度,从r往前的子串长度,以及区间[l,r]的子串长度,然后用锁区间线段树的写法query时直接返回结构体,跨越smid时重载一下运算符合并一下就行了。
树状数组
学会对各种东西建BIT,可以是值域,可以是区间,还有对某个权值,如前缀和建BIT的。
线段树合并
遇到动态加边时,可以用并查集维护根节点,把其中一棵树的根上的线段树合并到另一棵上并以之为新根,并查集要定向merge。
一般想到每个点开vector合并的东西都可以拿线段树合并写。
平衡树
Link-Cut tree
树链剖分
算法板块
迪法师
对于一棵树,有的题目可以把每个dep的点用vector存起来然后按照dep跑dfs,一般题目意思比较明显。
一定要理解统计语句放在dfs前后的区别。
博法师
跑棋盘类的题目,比如一个点到达的是一个矩形之类的,可以用对每一行用并查集把终点所在列缩起来,强制让每个点被遍历一次。
getid(x,y)=(x-1)*m+y,懂得。
getid(x,y,k)=((x-1)*m+y)*4+k),加入了一个点和它四周的某一点的状态,相当于分层图。
二分
模拟
贪心
靠智商吧QWQ。
有的题可以按二进制位贪心
A*
启发式合并&dsu on tree
字符串
hash
$SH[i]=(SH[i-1]*base\bmod p+s[i])\bmod p$
取出$[l,r]的hash$值:$hash[l,r]=(SH[r]-SH[l]*base^{r-l+1}+p)\bmod p$
如果维护集合且带删除的,可以个集合中的点赋随机值异或起来,这样就能删了。
hsah值和排序常连用。
kmp
trie
Trie上可以跑DP。
Trie可以解决许多字符串前缀的问题。
Trie解决异或最大值。
STL
vector
众所周知,vector+二分可以处理很多东西,,,vector<int>().swap(a)(a为vector)可以有效节省空间,真的有效。
set&multiset
可以重载运算符,自带二分查找且更快,对于维护有修改和删除的信息,或者第k大的信息,一般用这东西维护,删除set可以支持s.erase(val),s.erase(iter),set.erase(begin,end),multiset还是用s.erase(find(val))或者s.erase(iter)吧。
有的时候要在收尾加inf和-inf来判边界
map
可以用来节省空间,比如map<int,各种东西>a,相当于开了任意多个(各种东西),也可以时stl。map还可以看成一个pair,定义指针it:typedef<map<int,各种东西> >::iterator it,那么it->first就是前面的int,it->second就是后面的(各种东西),而且用it从a.begin(),到a.end()可以遍历当前map的所有元素,至于按照啥顺序,,,蒟蒻不知道,也不会有这么鬼畜的题目吧。。

浙公网安备 33010602011771号