2020.12noip考前知识点总结
想的很杂,平时的一些很常见的套路一时半会儿可能想不到,先顺着思路总结一些最关键的模型。
网络流
联赛基本不可能出现正解为网络流的题目,但是我认为这是最重要也最有价值去总结的方面。考察的知识点有限,决定了联赛的难题不在算法而在思路,其中贪心就是最典型的思路题。像上次的csp2019树上的数与csp2020贪吃蛇都是贪心。若策略实在是过于复杂,费用流虽然复杂度可能不对,但常常可以拿到救命的分数。最大流的对偶转化模型也很常用,还有联赛可能出现关于二分图的知识点,这个时候用(dinic)算法和一些技巧显然是非常优的选择。
常见模型:
1.Dilworth定理:图的最长反链长度等于最小链划分数,图的最长链长度等于最小反链划分数。处理偏序关系时是一个有效的工具。
2.DAG上的最小路径覆盖。最小的路径覆盖数等于点数减去最大匹配数。要求最小路径覆盖,就是要尽量用到原图中的边,每经过一次原图中的边就一定减少一条链。这个定理同上面的Dilworth定理,最大流最小割和二分图中的(konig)定理都是同源的,本质是线性规划的对偶规划。
3.上下界可行/最大流:核心的思想是补偿。建立虚拟源汇点,根据流量平衡将每个点连向源汇点得出可行流。最大流直接在可行流的基础上跑原图中的源汇点,"榨干"剩下的流量。
4.差分费用流:比如费用和一个差分严格单增的函数相关,就把流量拆开,费用设为差分。这样的题不算很多,比较常见的就是平方费用费用流。
5.最多不相交问题:最常见的就是在一个序列中每个点只能出现(k_i)次,每条覆盖边有一定的收益。拆点,将序列上的线段覆盖看做一个DAG上的转移。
6.分层图:一些涉及到限制的状态转移可以看作分层图中的流问题。但是一般来说这种方法的时空复杂度并不优秀,用上了就是打暴力。
7.最大权闭合子图:选择一个点必须选择其后继。这种符合转移单调性的问题通常可以拓扑排序,但是DP的时空复杂度比网络流更劣。还是考虑补偿的思想,S连正,负连T,求出图中的最大流。考虑若一条链的入流量更大,则一定选择S,最大流为T的流量限制,反之亦然。图的最大权就是正点权之和减去最大流。
8.最小割树:考虑分治处理。对于一个划分的点集,在两段选点,再根据最大流所得划分对应连边,将当前点集划分递归分治。原图中两点间最小割等于树链边上的最小权。
基本算法:
最大流(dinic),加上当前弧优化。费用流(spfa),至于(Dijkstra)费用流并不是那么显然,并且在实际问题中(spfa)费用流通常表现不错,基本够用。
计数,同余及数论
计数,同余理论和数论一般来说并不能直接归在一个板块里,但由于联赛中的数学一般不会涉及到较高级的数学知识点吗,一些计数题可能不用更为先进的方法都能解决,数论中的一些变换也远远不及各种反演的难度,目前没有必要过于关注。我认为只要不是压轴题,我应该解决数论,计数方面的问题。
常用工具:
1.二项式的最基本变换:如范德蒙德卷积,上指标求和,平行求和等,无论干什么都会用到。
2.斯特林数及其递推式:第一二类斯特林数的定义式与递推式
我认为斯特林数可能的用途在化简组合式子中的(i^j)类项为可递推预处理的项
看起来比较复杂,但是这个技巧实际上非常常用,在很多题目里面都是关键。
3.欧拉筛求各种数论函数,以及阶乘逆元的递推。基本知识,数学大厦的第一块砖,已经很熟练了。
4.Lucas定理:
在某些题目中是一个处理大数的方法。
5.欧拉定理:
虽然简单,但是对于可以处理输入特别大的题目。
数论知识博大精深,但是对于联赛上述足以,还有像BSGS这样的实用算法就算不知道也可以考场时发明出来。至于多项式,各种反演,快速变换都没有用武之地,先放一下。
尽管数论中有很多很多的定理和技巧,但是最重要的一定是打表,找规律才是正解。
图论
刨开网络流后,图论剩下的内容变少了很多。由于大部分题难度适中,有一定的思维量和代码量,又不算过于难为选手,我认为这次联赛一定有一道图论应用题。CSP2020的第三题就是一道图论题。
常见模型:
1.最短路:并不局限于算法本身。最短路可以解决的问题是费用流的子集,但是复杂度和常数通常来说更优。差分约束,利用(spfa)的三角不等式来求出一组满足约束的变量集。判断负环,基于(spfa)的遍历次数。还有如果不是与(spfa)性质有关的应用,最好写(Dijsktra)。
2.MST:并没有太多好说的,我没有听说过MST有什么很通用的变化技巧。
3.缩点:算是一个核心。有向图中,强连通分量(SCC)算法通过判断(low)是否等于(dfn)来新建分量。无向图中,分为边双与点双。点双不具有传递性,不能直接并查集合并。
4.拓扑排序:我认为联赛最爱的图论考点。一般的拓扑排序主要是在缩点后解决了状态后继性的问题,在DAG上对状态的转移。非常灵活,可以融入各种模型。csp2020T3就是用拓扑排序求出了转移序列,对每次加法操作计算出操作次数。
5.最小树形图:联赛尚未涉及到的知识点,谁知道会不会今年来一个惊喜呢?思路很直接,每次循环暴力找出可被扩展的点集,暴力合并,检查是否有剩余孤立点。
图的关键同网络流,在转化和建模上,这方面主要靠多观察分析。
DP
DP作为一个大类,其思想融入于所有问题中,比如状压的思路用途广泛。现在难以全部详尽,仅总结一些常规优化和设计思路。
常见类型:
1.数位DP:就是记忆化搜索。一般的数位DP基本都是计数,都涉及到多维状态,主要的优化方法就是优化状态。
2.区间DP:用于可以快速合并的信息。大部分区间DP可以改成顺推以优化复杂度。
3.概率DP:常见的概率DP涉及到后效性处理与状态之间的互相转移,基于高斯消元列出方程。
4.环形DP:断环成链,倍增处理。
优化方法:
1.状态压缩:将DP的状态用一个k进制数或串表示,达到节省时空复杂度的效果。有时候会用hash协同优化。
2.数据结构优化转移:有时转移涉及到一个区间或范围,可以用线段树之类的区间数据结构维护已知状态从而降低转移复杂度。
3.单调性:单调队列优化和斜率优化都可以归为此类。很多最优化问题中具有单调性,可以利用一个单调栈或单调队列,维护上下凸壳,单向决策以优化复杂度。除了直接维护单调数据结构首尾来转移,某些更苛刻的题目还要在上面二分。这样的优化可以很难,但是连普及组中都能出现摆渡车这样的题目,我认为这个技巧可能会被考察地很有深度。
4.状态设计优化:一般来说有了合适的状态,转移和决策自然就出来了。大部分在序列上的DP题与复杂度直接相关的就是状态的设计,每个状态至少遍历一遍,还可以有多个转移。
5.bitset优化:bitset提供了非常强的常数优化,可以复杂度从将(O(n))压缩至(O(frac{n}{omega})),可以抵掉一个(log),但是只能用于01状态表示。
6.滚动数组:一个看起来常见却非常厉害的优化。不仅是空间得到了飞跃,常数也会变小,开一个大数组是非常耗时的。
7.矩阵优化递推:对于决策在有限前项的DP,可以将每次转移写入一个矩阵,处理出2的幂次的转移矩阵,根据结合律加速递推。除此之外,还有一些图上的问题甚至字符串建成自动机的转移也可以搬到矩阵上。虽然求通项的(O(n))变成了(O(logn)),但是乘上了一个矩阵转移的(O(k^3))复杂度,实际运用时必须注意这个问题,矩阵的常数经常是一个问题。
DP的考察实在是太过灵活,每一题可能都会用到特殊的优化,泛泛而谈确实没有意义,只能实地分析。用血得到的教训,一定要好好分析数据范围。如果有一些不常见的,解题的关键基本可以肯定就在这里。
数据结构
联赛对于数据结构的难度很少有限制,树套树,平衡树,比较毒瘤的数据结构都出过了,就差分块了。涉及到的方法也很杂,各种各样的套路都有。
常见工具:
1.树状数组:几乎是每一年都会考到。作为一个辅助性的数据结构,树状数组通常用于在一些简单的地方加速运算。
2.并查集:看起来没有什么东西可说的,但是他的升级版扩展域并查集可以维护k分图,之前的关押罪犯就是一题。
3.ST表:处理的问题是线段树的子集,主要用来优化复杂度。最典型的应用就是配合欧拉序完成(O(1))树上LCA。有时候卡空间。
4.线段树:可以说是最普遍的数据结构了。维护各种区间信息。常见的变式有李超树,经典的(O(log^2))数据结构,用于维护优势线段。猫树,记录区间关于中点前后缀和,可以简化很多操作至(O(1)),但是很吃空间。最重要的就是极强的扩展性,唯一可以被魔改成任何东西的数据结构。
5.主席树等可持久化数据结构:作为持久化的应用反而不算常见,更重要的功能是维护区间可加性信息。这个东西很多想不到正解的时候,可以作为一个有效的暴力手段,不过空间是主要的问题。
至于更难的内容出现的其实并不多,数据结构也不需要总结太多,功夫还在平时。我认为数据结构题最重要的就是敢想敢写,就算他是个码农题也只是个联赛题,没有什么好怕的。
树上问题
以往真正的难点主要集中于树上问题,像天天爱跑步,疫情控制,运输计划等。这些题作为压轴题,码量大,细节极多,有的甚至有点卡常。也有直接把序列上的问题搬到树上的,但是通常难度都会翻倍。如何去写这种题或打出好的暴力是目前最重要的研究问题。
常用工具:
1.求LCA:最常见好写的就是倍增,时空复杂度和代码复杂度都很均衡。如果要优化就跑出欧拉序建ST表可以在(O(1))的时间内求出。
2.求直径:直径有很多性质,如果是涉及到树上长度的最优化问题很可能与直径有关。求法就是2遍dfs找出端点。
3.求重心:同直径,重心一般会出现在涉及子树大小问题的技术和最优化,求法直接在dfs时找出最大子树大小最小的点。
4.树链剖分:解决大部分树上问题的通法,将树剖成若干条链,利用线段树处理。最常见的当然是重链剖分,根据子树大小对树划分。树本身的属性加上线段树的复杂操作,实在过于灵活,难以一言以蔽之,只能实地分析。
5.欧拉序/dfn序:记录了结点间的祖先关系,可以在一些难以发现的地方起到关键的作用。欧拉序ST表求LCA就是一个很巧妙的应用。
6.树上启发式合并:基于树链剖分的算法,用启发式合并的分析方法加上树链的上界限制改变转移顺序以优化暴力。可以吊打树上莫队这种难写难调的算法,也是一个部分分神器。
优化树上问题的算法还有很多,但是大部分,像虚数,动态树,点分治这些稍微上一点档次的技巧应该不会用上。如果真的很难,对于我这样的一个暴力选手,就应该准备乱搞偏分。
一些暴力方法
总结了那么多,实际上最重要的还是打暴力,我的实力不足以切掉所有题,暴力是最重要的手段。
常用手段:
1.莫队:我不知道联赛是否会有很难的序列操作问题,如果我做不出来,那么莫队是应该第一时间考虑的选择。莫队在使用时可以根据题目和数据调整块长,会有巨大的作用。还有回滚莫队,对时间操作的带修莫队。
2.随机化贪心:联赛中出现基本不可能出现随机化贪心的问题。随机化贪心的算法,退火,爬山,适用的数据范围其实很有限,比较小的部分分我也能直接拿到。如果实在下不了手,最后再想随机化贪心。
3.IDA:找不到合适的状态只能搜索时,除了设计更好的剪枝,可以加上迭代加深,将最优化问题转化为判定问题。
4.贪心:贪心应该是一个很重要的内容,但是除了一些基本的思想之外实在是没有什么值得多说的。只能想办法从多方面分析题目,观察信息。
5.打表:在一些数学推导已经到尽头而没有更多思路的时候,直接打出一张表,对着表找规律,效果优于任何推公式的挣扎。
6.善用STL:没有时间造轮子时直接上STL,有时候可能效率欠佳,但是至少比没有好。vector实现的"平衡树"很多时候非常有用。
暴力最重要的还是多想,找出多少条件就用多少,好多次暴力写着写着就成了正解。
知识是总结不完的,还有博弈论,字符串等也有内容,但是在联赛中并非最主要的重难点,暂且略过。总结了这么多,最重要的是观察和分析。