『正睿OI 2019SC Day6』
<更新提示>
<第一次更新>
<正文>
动态规划
\(dp\)早就已经是经常用到的算法了,于是老师上课主要都在讲题。今天讲的主要是三类\(dp\):树形\(dp\),计数\(dp\),\(dp\)套\(dp\)。其中计数\(dp\)是我很不熟的,\(dp\)套\(dp\)是我没接触过,树形\(dp\)难的题我也不是很会做,所以感觉还是收获了不少,于是\(dp\)的总结将主要会以题解的形式呈现。
重要例题及简要题解
\(Gcd\ counting\):设\(f_{u,v}\)代表以\(u\)为根的子树中,点权都能被\(v\)整除的最长链长度。对于每一个节点,只枚举它的因数,于是可以进行转移。
\(You\ are\ given\ a\ tree\):对于一个给定的\(k\),可以树形\(dp\) \(O(n)\)地计算答案,每次优先选子树内成立的方案,然后再考虑向上延伸即可。不难发现\(f\)数组不同的取值个数只有\(\sqrt n\)种,并且具有单调性,可以二分找段边界。
\(Vladislav\ and\ a\ Great\ Legend\):考虑拆一下式子\(x^k=\sum_{i=0}^kC_{x}^i*i!*S(k,i)\),其中\(S(k,i)\)是第二类斯特林数,表示将\(k\)个元素拆分成\(i\)个集合的方案数。然后化简一下就发现要求\(\sum_{X}C_{f(X)}^i\),涵义为所有非空点集对应的生成树标记了\(i\)条边的方案数之和。然后可以\(dp\),\(f_{u,v}\)代表以\(u\)为根的子树中标记了\(v\)条边的方案,背包即可。
\(Uniformly\ Branched\ Trees\):考虑做树同构是要找重心的,那么\(dp\)计数肯定也要找重心作为根。设\(dp_{i,j,k}\)表示节点数为\(i\),共有\(j\)棵子树,每棵子树的大小都不超过\(k\)的有根树数量,然后\(dp\)。考虑单重心和双重心分别统计答案即可。
\(Multiplicity\):设\(p_{i,j}\)表示使用了\(a\)序列的前\(i\)个元素,造了长度恰好为\(j\)的子序列的方案数,第二维只需枚举因子转移,滚动数组即可。
\(Maximum Element\):考虑计算的函数返回正确的方案数,设\(f_i\)代表\(1-i\)的排列中有多少个是正确返回的,化简式子发现可以\(O(n)\),\(dp\)计算即可。
\(Hero\ Meet\ Devil\):很经典的一个\(dp\)套\(dp\),我们要把\(LCS\)的\(dp\)数组\(f\)压起来当作状态,于是想到差分。设\(f_{i,S}\)代表\(T\)串考虑到了第\(i\)位,\(LCS\) \(dp\)数组差分后压缩为状态\(S\)的方案数,内层\(dp\)可以预处理,外层\(dp\)直接转移即可。
\(XHXJ’s\ LIS\):考虑二分求\(LIS\)的\(dp\)做法,就可以\(dp\)套\(dp\),由于二分做法中栈内元素是单调的,所以直接把每个数字是否出现再栈里压成一个状态,然后在外部做数位\(dp\),状态为\(f_{i,op,S}\)代表考虑了\(i\)位,与目标值大小关系为\(op\),\(LIS\)栈状态为\(S\)的方案数,可以直接转移。
数据结构
这次老师的数据结构也没有具体地讲算法,都是讲例题的。考虑到有些题还有有点套路,没有详解的必要,于是这里就写了个别有价值例题的题解。同时,我在这里理一个表,简单地写了我对各类数据结构和数据结构类算法的理解。
重要例题及简要题解
\(1.\) 树链权值交:考虑序列上的版本,我们将第二个序列的值改为原数值在第一个序列上出现的位置,那么问题就转化为了在二个序列的区间内求在某个连续范围内的数字个数,可以用主席树解决。树上也是同理,只需对第一颗树链剖,对第二颗树建主席树即可。
\(2.\) 整除路径统计:考虑点分治,可以对每棵子树内的路径先计算最大值和权值和,然后考虑合并。把二元组按最大值大小排序,于是枚举一个点就确定了最大值,权值和直接在模\(p\)意义下处理,就能直接推出剩下一半最权值和需要是多少,用桶统计即可。
数据结构及数据结构类算法的理解
并查集
维护无向图连通性的有利工具,可以扩展为带撤销操作,多个意义的域或者是带边权等,有向关系可以转换为\(2-sat\)模型。
树状数组
用于维护前缀和,支持修改和快速查询。可以扩展支持区间修改区间查询,也可以扩展到二维前缀和。在值域树状数组上倍增,可以实现查询第\(k\)大。
线段树
序列维护区间信息的工具,前提要求是信息具有区间可加性,能够区间合并。当线段树作用在值域上时,还可以二分查找第\(k\)大。树上统计问题可能会用到线段树的合并算法,特别是用来计数的值域线段树。还可以维护扫描线算法,或者用来优化建图。
分块
一种暴力算法,可以维护各种各样的信息。当需要维护的信息难以处理时,就可以考虑分块算法,主要问题在于思考如何处理整段信息和如何处理边界信息。可以扩展到树上,实现块状树。
点分治
用于树上路径统计,常用的有两种方法:子树用数据结构维护的统计方法和先跑下所有子节点信息再统一计算贡献的统计方法,可能需要结合其他数据结构或计数算法。
cdq分治
主要作用有三种:\(1.\) 解决偏序问题 \(2.\) 加速或维护动态规划 \(3.\) 处理动态的数据结构问题,化动态为静态。 对于\(1\),核心思想在于部分有序的排序过程,对于\(2\),核心思想在于计算左半边对右半边的转移,对于\(3\),核心思想在于计算修改操作对查询操作产生的贡献。适用范围较广。
整体分治
对所有询问同时进行二分答案,于是就可以对询问和修改操作进行分类处理,以得到格式相同的子问题,进行分治。对于限制较多,维数较高的数据结构问题可以考虑。
线段树分治
也是时间分治算法的一种,和\(cdq\)分治很像,不过使用线段树来记录时间线上的信息,处理询问时只需\(dfs\)即可,回退时需要支持撤销操作。
Treap
维护值信息的有效工具,功能较多,一般来说可以用值域树状数组和值域线段树代替。
Splay
可以提取子树,操作区间的平衡树。使用范围较广,对于较复杂区间问题可以考虑。
LinkCutTree
解决动态树问题时考虑使用,可以维护链信息,需要\(splay\)辅助。
trie/可持久化trie
处理字符串问题以外可以处理异或最大值,可持久化就能处理区间异或最大值。
主席树
前缀和版的线段树,可以利用前缀和的区间可减性实现对一个区间内的所有线段树进行操作,当然可以当可持节化线段树用。
莫队
用来处理区间问题,要求区间支持转移。当转移受限时,可以拓展到回滚莫队,当有修改操作时,可以拓展到带修莫队。当然使用\(dfs\)序搬到树上是可以的。
树链剖分
将树上路径问题和子树问题转化为不超过序列问题,再利用其他数据结构实现对序列的维护。
<后记>