zxy的思维技巧

如果觉得这篇博客写得好的话不妨点一个推荐我怎么沦落到求赞的地步了

0.更新日志

我尽量在本篇博客总结我遇到的所有思维技巧,希望深入理解之后能形成思维网络。

本篇博客的选题很多都是 \(\tt CF\ 3000+\) 的题,具有很高的思维难度而非代码难度。

\(2021/8/10\),把 \(dp\) 开了个头。

\(2021/9/30\),继续更新 \(dp\) 部分。

\(2021/10/8\),继续更新 \(dp\) 部分。

\(2021/10/14\),继续更新 \(dp\) 部分。

\(2021/10/29\),感觉复习慢一点也没关系,一定要尽量自己推出来,懂得完整的逻辑链条然后从中提取我所缺失的精华,这才是复习的目的,继续更新 \(dp\) 部分。

\(2021/11/8\),终于开始复习图论啦,现在看来退役之前肯定更不完了,把这个技巧性强的复习完就满足了吧 \(qwq\)

\(2021/11/15\),每次找判定性条件,一定要找必要条件,我已经因为没有往这方面想受到重创了。

\(2021/11/19\),真他吗退役之前更不完了,\(zxy\)\(zxy\) 之前暑假定下的不断更目标你忘了吗?

\(2021/12/21\),退役一个月之后回归,以后养成好习惯,新写一道题的题解之后就放上来。

\(2022/2/9\),怎么马上就要省选了啊,省选之前争取基本完工吧,这东西真的就是我的遗产了。

\(2022/3/30\),开始涉足一些以前没有整理过的板块。

\(2022/4/10\),字数上万了,这篇博客称为 \(\rm 3A\) 大作不过分吧?

\(2022/7/19\),正式开始 \(\tt NOI\) 之前为期一个月的复习计划。

\(2022/7/27\),稳步进行复习中,大概在 \(8/6\) 结束第一阶段的复习,在 \(8/10\) 结束第二阶段的复习(整理贪心\(\&\)数据结构)。然后重读这篇博客,找出遗忘的地方再次复习,多推一推思路总是好的。

1 dp

1.1 常规dp的思维过程

1.1.1 问题转化

  • 比如你要让所有点被覆盖,那么状态可以设计成覆盖一段前缀,并且中间不允许出现断点:CF1476F
  • 序列上的路径问题,可以转化成起点和终点的匹配问题,\(dp\) 匹配的权值,记录匹配的标记就可做:The Karting
  • 多过程的题,不妨考虑末状态具有什么性质,直接对末状态进行计算。比如一类期望题中,某一种方案的定义方式最后导出等概率出现,就可以直接对此方案计数了:绿宝石之岛
  • 高维的问题,可以通过技巧拆分成不相关的低维问题,比如 \(45\) 度旋转:Jumping sequence
  • 尽可能的简化问题也是问题转化的一部分,比如把具有平行关系的点缩在一起:Black, White and Grey Tree
  • 计数问题中任何性限制原则上优于存在性限制,可以通过切换限制主体来完成转化:Reunion
  • 子序列问题可以通过证明不交转化成区间问题,要向简单的 \(dp\) 模型靠拢:AmShZ Wins a Bet

1.1.2 发掘性质

理清思路真的很重要,拿到题你可以先想想什么东西在什么情况下合法。

  • 什么时候需要你去发掘性质?当你发现直接 \(dp\) 需要考虑的情况太多了,你可以手玩找一些最优解需要满足的必要条件,才能让你的 \(dp\) 有的放矢,例题:CF1368H1Division into Two
  • 性质是针对限制而来的,在限制较少的题目中可以去往考虑更少情况的方向猜性质:CF573D
  • 在具有强烈过程性的题目可以往结果的方向猜性质:To Make 1模拟赛2-AEternal Average
  • 很多时候讨论特殊情况可以得到很好的性质:泳池(讨论 \(0\) 的情况可以得到调和级数的性质)
  • 如果限制的主体数量级巨大(比如集合、子序列),那么可以考虑归纳、递归的方法描述限制。并且使用这种方法还有一种好处,就是递归子问题很容易拓展到 \(dp\) 的形式:Density of subarrays

1.1.3 思考决策状态

  • 可以先使用枚举法帮助思考我们需要决策的状态,然后用 \(dp\) 加速枚举的过程:Sorting BooksInsertion Sort
  • 计数题可以想一想需要知道什么量可以用计数原理快速算方案,然后我们用 \(dp\) 决策这些量即可:一拳超人
  • 可以选取一种基状态,其他状态可以由基状态修改而来,这时候尽量把问题改成多个量选\(/\)不选的问题,也尽量把他们的影响独立开来,然后用 \(dp\) 决策这个过程:New Year and Binary Tree Paths
  • 如果是决策的最终状态,且有多种方式可以到达同一种最终状态,那么强制只用其中一种方式:Mr. Kitayuta's Gift

1.1.4 选定dp主体

我们知道,\(dp\) 的本质是枚举所有状态,但是这些状态必然有一个载体,所以我对 \(dp\) 主体的理解是他只是一种状态的表示方法,我们用它来描述状态,但是状态是最重要的

很多时候你会遇到很多奇怪的 \(dp\) 主体,但判断它们的唯一原则就是是否能考虑所有状态,选 \(dp\) 主体的时候容易被思维定式局限,所以思考可以从哪些方面来描述状态是重要的,这里有一些关于选定 \(dp\) 主体的例子:

  • CF1474F:选 \(x\) 轴为 \(dp\) 主体是不容易的,但是因为我们通常是按顺序考虑子序列所以很容易陷入这个误区,选 \(y\) 轴为 \(dp\) 主体问题就迎刃而解了,所以对偏序关系更高级的理解是若干个限制,不同的题需要从不同的限制入手。
  • 卡农:并不一定以小处为主体,比如这题主体为数不好做,但是主体为集合就可以直接转移了。
  • CF1463F:遇到集合最优化问题时,可以考虑在值域上规划,选值域为 \(dp\) 主体。

1.1.5 设计dp状态

  • 只保留和代价计算有关的量,比如如果代价只和数量有关,并且如果可以通过数量还原出集合,我们可以把状压的一维改成线性的:CF1188D
  • 当状态很大的时候可以考虑通过枚举来把某些量拿出状态里面:Game with Cards
  • 当问题前后相互影响时,可以考虑把全局变量定义到局部状态里面:密室逃脱;如果操作是全局的,上面的方法也很好用:Red and Black Tree
  • 把和限制紧密贴合的量设计到状态里面,阴间出题人可能会用题目描述来引导你设计非常慢的 \(dp\) 状态,做一些基本的题意转化即可:皮配
  • 可以设计相反的状态,比如最小花费步数转化为最大减少步数,可能转化后更贴合题设:Paint

1.1.6 确定dp顺序

听着,所谓 \(dp\),最重要的是顺序。无论是考虑限制的顺序,还是计算贡献的顺序,一定要着重思考,我觉得它和结论题中的必要条件有着相同的地位。

  • 治疗计划:如果操作是有时间顺序的话,我们很容易被局限于时间中,另一种思路是考虑操作的主体,考虑主体的关系时把时间的影响考虑进去,所以 \(dp\) 不一定按时间。
  • 一拳超人:如果一个东西对另一个东西有单向的影响,那么先处理前面那个有助于考虑影响。
  • Kyoya and Train:图问题中,要注意转移顺序,通常这一维时单调的就可以作为顺序维,比如时间。
  • 集合选数\(dp\) 顺序尽量让限制紧凑一些,我们也许可以在独立的前提下篡改顺序。
  • Singer House:注意 \(dp\) 的顺序和方案的顺序是有区别的。比如对于路径计数问题,如果我们按照序列从左到右 \(/\) 树形自底向上的 \(dp\) 顺序计数,那么达到的效果就是若干条有向链合并的过程。
  • MEX counting遗迹:可能需要根据限制的特性,提前\(/\)延迟确定一些元素的过程。
  • The Hanged Man:选取合适的 \(dp\) 顺序,可以减少 \(dp\) 状态。

1.1.7 寻找子问题

  • 这部分我觉得可以总结一些核心的思想:寻找子问题最重要的是找状态之间的相似性,所谓相似性的含义就是信息记录在子问题中的一部分的占比,相似性越大你写转移就越容易,这需要你强大的观察能力:stars;要去构造问题之间的相似性,比如染色问题中可以通过钦定不变色来获得相似性:Shrinking Tree
  • 寻找子问题要考虑消除后面操作的影响,这样才能保证没有后效性:如果某个元素对于前面的影响是长远的,但又只能考虑一小步转移,那么寻找当前问题的等效子问题,就可以把这个影响传递下去,完成转移:stars;或者可以通过枚举法来消除所谓影响:Lanterns
  • 当考虑一小步不能很好的归纳到子问题时,可以定义一个辅助数组来解决这个中介状态:矩阵、统计问题中若当前不能计算代价,可以设计辅助数组把代价存下来:消失的运算符
  • 枚举法制造限制来划分子问题,比如顺序匹配问题中可以枚举空位:CF1439D

1.1.8 考虑如何转移

  • 转移的大步小步。小步适于考虑转移,但是可能会消耗更多时间;大步常常会很复杂,但是可能起到加速的效果。在大步小步之间切换,才能写出合适的转移:Appleman and a Game

  • 转移中存在的限制很烦,在一些计数问题中,对于多个元素的限制可以考虑某些元素任意选,另一些元素为了满足限制而具有确定的选法,计数 \(dp\) 中选择的顺序是十分重要的卡农

  • 如果确定转移顺序之后前后会相互影响,那么在后影响前的时候可以通过枚举来解决这个影响,再归纳到子问题:CF1476F

  • 多个对象的决策问题中,通常只考虑最后一个对象的决策:CF1439D

  • 正难则反是很重要的技巧,比如在计算第一次到达的方案数的题目中,容斥掉的项就是子问题:逃跑

  • 转移的时候适当的算错,可能会让转移简洁很多:常见的模型是算错但是一定不会作为转移点 link;还有是算少但是最优解可以被统计到:Gerald and Path

  • 复合 \(dp\),设计多个 \(dp\) 状态,互相转移的方法是很值得思考的。其实我感觉它的原理还是分步思想,把一个较为复杂的问题拆分成若干个部分解决,这些部分中可能又蕴含子问题:模拟赛6-A;或者是多个 \(dp\),一个 \(dp\) 用于拆分,一个 \(dp\) 用于解决被弱化过的问题,通常可以得到很好的性质:CF1439D泳池

  • 可以把限制的判断拆分到转移中进行:泳池遗迹

1.2 常见dp优化方式

1.2.1 斜率优化

  • 有些题很难看出需要用斜率优化,把和状态有关的量当成常数,把只和转移点有关的量当成纵坐标,把交叉项系数当成横坐标,把转移点的某个量当成直线去切即可:CF1067D
  • 另一类不常见的斜率优化是,变形出斜率的形式,维护凸包:国王饮水记

1.2.2 决策单调性

定义:对于 \(a<b<c<d\),若 \(f(c)\)\(b\) 转移比 \(a\) 优,那么 \(f(d)\)\(b\) 转移也比 \(a\) 优。

判断式:\(w(j,i+1)+w(j+1,i)\geq w(j,i)+w(j+1,i+1)\)

通用实现:把决策点拿去分治,每次更新中间位置的状态,然后把决策点划分到两边。

1.2.3 考虑有效转移/状态

  • 只去计算和答案有关的状态(也就是减少状态的数量),当前前提是转移不出问题:Rescue Niwen!;如果答案是和式,那么可以把状态也定义成和式:Student's Camp
  • 在某一种特殊情况下一种转移的方式会变少,可能达到复杂度级别的优化。序列上可以考虑区间交\(/\)不交情况下的有效转移:Communism
  • 两种转移的时候选一种为主体,另一种在它的基础上对答案有影响的时候就是有效转移;并且如果一种状态明显超过了需要考虑的范围(就算在价值上它是更优的),你也不需要去考虑它:CF771E
  • 从某个点转移一定比另一个点转移要优,看起来很朴素的结论却能在很多时候有奇效。它可以让转移点的数量大大减少:Bank Security Unification;也可以忽略到一些恶心的限制(不合法的点一定不优):模拟赛4-A;也可以利用贪心大致筛选一些有效转移:Professional layer

1.2.4 讨论法

  • 整个问题重要的量可能很多,都需要用状态表示出来,但某些情况下有用的量可能会减少,这时候可以分类讨论,互相转移:Favorite Game
  • \(dp\) 的取值很少且是分层转移的,可以讨论并用数据结构维护状态:Split
  • 图论问题可以讨论掉一些较小的环来降低复杂度:Abandoning Roads
  • 讨论法很适合处理环形 \(dp\) 问题。环形 \(dp\) 的关键是:断开哪一条环边(我们想要环边具有怎样的特殊性质);断开环边局部的状态是怎样的(简单讨论可以解决):Sonya Partymaker

1.2.5 等价类

  • 在很多图论问题中状压环的时候,如果转移只和环的大小有关,那么可以把相同大小的环看成一个等价类:CF1466H
  • 只和数量有关而和顺序无关可以按照数量划分等价类:Mr. Kitayuta's Gift
  • 乘积不超过某个数的题目可以考虑通过逆向整除分块来划分等价类:Ridiculous Netizens
  • 转移方式相同而且易于计算总方案数,可以把它们划分为等价类:逃跑

1.2.6 数据结构优化

  • 对于数列覆盖问题,常有的结论是两个点的覆盖范围要么包含、要么相离,这时候可以选择用单调数据结构维护(因为覆盖范围单调),而不是带 \(\tt log\) 的数据结构:CF1131G
  • 发现题目有不可解决的维度时,要敢于使用数据结构。但是此时空间消耗特别重要,注意处理 \(dp\) 的顺序,才能时数据结构的使用简单化,并且减少常数的消耗:购票

1.2.7 解决巨大数据范围

  • 离散化是解决较大数据范围的一种方式,如果某一段内转移相同,可以离散化出段然后矩阵加速:CF1474F;或者记录离散化段内的信息转移:划艇;离散化还可以把连续型问题转化为离散型问题:Random Ranking
  • 可以找循环节,只要不同的循环节之间没有多的限制就行,然后每个循环内部都取最优解。证明的关键在于没有构成完整循环的那部分,可以考虑调整法证明(具体思路见例题):CF1463F
  • 对于最优化的 \(dp\) 问题,可以去找转移点的结论,知道每个转移点转移多少次就可以矩阵加速了:CF1067D

1.2.8 考虑转移路径

  • 转移路径可以形象化地表示出来,那么可以把简单的 \(dp\) 转化成计数问题,比如这里二维简单 \(dp\) 转网格图计数:[JLOI2015]骗我呢
  • 考虑 \(dp\) 的组合意义可以建出图论模型,快速计算时直接枚举其中的某个量:匹配字符串

1.2.9 费用计算优化

  • 如果当前状态不好知道,但你清楚代价的变化规则时,可以费用提前计算:Candles
  • 如果代价是全局的,那么可以费用延后计算(但一定要注意有无后效性啊??):Red and Black Tree

1.2.10 分治优化

  • 背包问题中如果只有一种元素会特殊,那么可以用分治优化,每次保留本层最优解传递上去即可,复杂度会优化的原因是分治会通过在部分中竞争保留最优解:篮球
  • 只要是对于一段区间只有加入就可以尝试线段树分治,不一定要是序列上的区间,可以是先建立树形结构之后,对于一段 \(\tt dfn\) 区间的修改:序列
  • 如果只有一个位置不加入,也可以直接分治优化:Random Ranking

1.2.11 神奇优化

  • 当转移代价无法优化时,可以考虑转移点数量的限制,然后快速找到转移点:绯色IOI
  • 不支持取 \(\max\) 操作时,可以通过考虑转移点的性质来转贪心,通常是权值单向影响的题目:CF878E
  • 如果 \(dp\) 值单调,并且需要支持合并和取最值,那么可以用 \(\tt set\) 维护差分标记:魔法树
  • 如果 \(dp\) 代价为正并且只存在于单点上,那么可以考虑成类最短路,每次拿到最小的那个能扩展就扩展,用数据结构维护最容易被扩展的点即可(通常是线段树维护最值):治疗计划
  • 整体 \(dp\),如果多个 \(dp\) 转移方式完全相同,那么可以考虑一次 \(dp\) 求出答案,比如序列上可以通过端点初始化和端点统计完成:Extreme ExtensionForeigner星图;更加灵活的形式是找问题之间的关系:Palindromic Hamiltonian Path;其他例子:Mr. Kitayuta's Gift山河重整线段树

1.3 常见dp模型

1.3.1 树形dp

  • 树背包真正的复杂度是第一维大小乘上第二维大小,特别是第二维很小的情况:CF1097G
  • 建立一些使用于特殊性质的树形结构,并在结构上规划:浅谈笛卡尔树结构的应用
  • 树重排规划问题可以考虑转区间 \(dp\),本质上就是枚举根的过程:Tree Tweaking
  • 路径规划问题,可以枚举起点,然后使用换根 \(dp\) 来获取最优的起点:Svjetlo
  • 合并问题可以从叶子开始考虑:Logical Operations on Tree
  • 树上路径的限制问题,可以只保留最深的\(/\)最浅的记为状态转移:命运
  • 不支持合并的树形 \(dp\) 问题可以考虑转成 \(\tt dfn\) 序上 \(dp\)(树上依赖背包):Ridiculous Netizens

1.3.2 状压dp

1.3.3 连续段dp

  • 连续段 \(dp\) 可以计算端点产生的贡献,这是和连续段数正相关的:摩天大楼
  • 写转移的时候可以用两段之间任意长这个条件,方案数就便于计算了:Phoenix and Computers

1.3.4 背包

  • 如果装入的总物品不是很多(\(\sqrt n\) 级别)并且连续,可以考虑柱状图 \(dp\),转移分为增加一个柱子和把所有柱子整体升高:逆序对山河重整;而且这种 \(dp\) 天然带有顺序,如果你想求前 \(k\) 大的话是特别方便的:绿宝石之岛
  • 多重背包如果只需要判定存在性,可以维护还剩下的物品数量,转完全背包:AB tree
  • 如果背包支持快速合并(有凸性),那么可以直接用分治优化:妹妹卡组
  • 要有一个总体是时间观,很多巧妙的背包优化只能把 \(n\) 变成 \(\sqrt n\),如果需要本质复杂度的下降,那么可以尝试改变维护的东西,降维是常用的技巧:Tree Degree Subset SumJumping sequence,降维的关键就是找独立性之后拆分:皮配
  • 有一个物品是特殊的,它的选取方式和其他物品不一样,特殊考虑它就能让问题变简单:Lucky Numbers;少量特殊物品时可以考虑分别计算然后合并背包:皮配
  • 很多时候背包会存在(隐藏的)拓扑关系,这时候的结论可能是选了小价值物品就必须选大价值物品:Turtle
  • 总容量大,但是物品重量很小的背包,可以按二进制位考虑压缩有效状态数:物品
  • 前后缀背包,把这个思想搬到树上就是求出 \(\tt dfn\) 正序背包和 \(\tt dfn\) 倒序背包,然后再合并:苹果树

1.3.5 计数dp

计数 \(dp\) 的原则是:初始有一些基础方案,然后我们逐步添加可以区分出方案的东西(这东西是根据方案不同的定义来的),转移到不同的地方就代表这一步产生了不同的方案:高维游走

  • 组合意义的嵌套的重要的方法,也就是我们给我们的代价函数确定一个组合意义,那么 \(dp\) 就需要同时完成确定局面和组合计数的功能,常用技巧是拆分:Pass to NextStranger TreesCrash 的文明世界
  • 巧妙的枚举可以达到合并两个子问题方案的目的,比如本题枚举可以合并组合数:CF1097G
  • 如果判断合法需要使用 \(dp\),而原问题又是一个计数问题时,可以使用 \(dp\)\(dp\),其关键还是建出 \(\tt DFA\)模拟赛7-A游园会

1.3.6 杂项

  • \(dp\) 维护直线函数:CF889E
  • \(\tt slope\ trick\) 优化 \(dp\),主要处理代价带绝对值的规划题目:折线算法;可以维护很多跟斜率有关的操作,比如含有 \(\tt max\) 的函数:Increment Decrement
  • \(dp\) 维护容斥系数,在大小关系中的计数题中十分常见:小D与随机不等关系;一些需要考虑集合的毒瘤题中,暴力指数级容斥出奇迹,再转 \(dp\) 维护即可:猎人杀百鸽笼

2 图论

2.1 图论问题的思维过程

2.1.1 图论模型的建立

首先考虑对于原问题的什么对象建立模型(主体的选取),然后尝试用图论的各种意义去表示原问题中的元素(比如点权、边权、路径、连通块\(...\)),这两步都不要被定式思维所限制。

以题目中的一个限制为基础建立模型,这一步不要被思维定式所局限。

  • 遇到难以处理的全局限制时可以考虑图论:Maximum Adjacent Pairs
  • 矩形中类似推箱子的问题,可以把箱子的移动转化成空格的移动,建立关于空格移动路径的图:Shifting Dominoes
  • 区间元素和的判定问题可以把前缀和建成点,原图中的元素建成连接前缀和的边:Flip and Reverse

2.1.2 图结构的分析

  • 树形结构具有很多优美的性质,可以通过分析度数与环来证明树形结构:Shifting Dominoes
  • \(dfs\) 树是很重要的思维方式,通常我们分析树边和非树边能得到很多有意思的性质。如果是有向图还要考虑哪个点为根更好分析:James and the Chase;或者可以通过 \(\tt dfs\) 树直接给出构造:Nezzar and Hidden PermutationsWeighting a Tree
  • \(\tt DAG\) 具有很好的性质,所以就算是遇到一般图时,也可以先思考在 \(\tt DAG\) 的环境下如何处理:Sergey's problem

2.1.3 问题转化

  • 度数和连通性常常可以互化,但度数描述单点限制,连通性描述整体限制:电报
  • 图论中拆分思维也很重要,把总贡献拆分到点上\(/\)边上:Keys
  • 如果不同的限制具有拓扑关系,根据题目特性可能可以忽略一些限制:Falling sand
  • 一类东西只贡献一次的问题可以考虑转化成匹配问题:Maximum Adjacent Pairs
  • 可达性问题可以考虑转化成连通性问题,此时注意考察连通的双向性和等价性:Cow and Vacation

2.1.4 寻找结论

2.2 常见算法应用

2.2.1 最短路

  • \(\tt dijk\)遍历思想在很多题中有大用处,如果每个点只需要遍历一次那么维护最有可能遍历的点:Mike and code of a permutation治疗计划
  • 动态加边可以解决到达时间最小的限制,它的本质是如果具有连通性就可以说明最早到达:Dirty Arkady's Kitchen;动态加边还可以直接维护强连通性,对正反图动态 \(\tt bfs\) 即可:图函数;动态加边还可以完成版本之间的转化,结合 \(\tt spfa\) 可以做到某些情况下的动态最短路:道路堵塞
  • \(\tt dijk\) 可以保证一些特殊的转移顺序:Intergalaxy Trips
  • 环上的最短路,如果数据范围极大,先考虑重构环之后再扫环:Drazil and His Happy Friends
  • 删点后求最短路的问题有固定套路,就是考虑有一条边一定会跨过这个点,可以拼凑出路径来:风之轨迹道路堵塞

2.2.2 连通性

  • 互达问题可以思考连通性,连通性重要的一点是传递性,有些问题可能只有特殊点具有连通性:Cow and Vacation
  • \(\tt lct\) 可以维护动态边双连通分量,考虑把非树边的影响转化成赋值标记即可:Bear and Chemistry
  • 无向图路径的最值问题,可以将边权排序之后转化为维护连通性(最小生成树只是特例):路径查询
  • 对于带修改的问题来说,可以有一个统一的固定结构来处理两点连通的时刻(边起作用的时刻):Gates to Another World;维护强连通性,可以用整体二分求出每条边强连通的时间,然后转化成维护无向图的连通性:WD与地图

2.2.3 拓扑排序

  • 拓扑排序可以提供一种解构图的顺序,注意拓扑排序中天然带有的可达性:Pink Floyd;如果需要一些出现顺序的关系,可以先建立图之后考虑其拓扑序:Insider's Information
  • 拓扑排序的性质,同在队列里的点没有任何到达关系,可以通过它来筛选合法点:Upgrading Cities
  • 拓扑排序的另类形式:按 \(1\sim n\) 的顺序在反图上 \(\tt dfs\),最后回溯的顺序就是拓扑序:Mike and code of a permutation

2.2.4 将问题转化到图论算法

  • 调整法可以帮助建出差分约束限制,矩阵问题可以以行和列为待定变量:矩阵游戏
  • 拓扑排序可以解决带平局的博弈问题,首先全部设置为平局,按照定义对反图跑拓扑即可:Shiritori
  • 差分约束的反向应用,如果要求是不出现负环,那么等价于有差分约束的合法解,那么可以把图上的边都写成不等式:Negative Cycle
  • 二分图染色问题,如果需要优化连边,得到同色的性质可以缩成一个点,然后套用并查集路径压缩的时间复杂度:港口设施

2.3 树问题

知识点:树的直径(邻域理论)、树的中心、链剖分、虚树、树分治、树合并、树哈希。

2.3.1 问题转化

2.3.2 树上算法

  • \(\tt lct\) 有着特别重要的染色模型,也就是用实边代表同色,虚边代表异色,修改就是把一个点到根的路径染色,然后用数据结构维护颜色的方法:Matches Are Not a Child's Play树点涂色
  • 延迟贪心,即能不放置关键点则不放置,这样能把关键点放置在最浅的位置:Squid Game
  • 要快速计算虚树的大小时,可以考虑下标为 \(\tt dfn\) 序的线段树来维护:语言;这种用线段树去重的方法还可以应用于字符串中(若干后缀的本质不同前缀,\(\tt sam\) 上启发式合并):Asterisk Substrings;这类线段树合并的本质是用线段树的结构提供了一个合并顺序:三角形
  • 最大\(/\)最小边权问题考虑 \(\tt kruskal\) 重构树。比如想要求虚树的最大边权,可以转化成重构树上最浅的祖先,即 \(\tt dfn\) 序最大点和最小点的 \(\tt lca\)Groceries in Meteor Town
  • 路径问题考虑点分治,不要被复杂的形式给诈骗了:Network

2.3.3 常见模型

  • 连通块问题的常用解决方法:可以在连通块的最浅点统计这个连通块的贡献,那么用树形 \(dp\) 来规划这个最浅点即可:切树游戏Ridiculous Netizens;还可以用 点数-边数=1 的经典容斥:完美的集合;选取连通块的代表点时,可以套用点分树这种分治结构:成都七中Ridiculous Netizens
  • 还原树的问题中,可以分步还原,也就是先还原特殊点的结构,再还原整体的结构:Restoring MapNew Year and Forgotten Tree
  • 边权和贡献最大问题可以往长链剖分这个角度考虑,如果是路径问题可以通过 \(2k\) 个叶子的构造性结论转化成最长链问题(前提是需要定根):Spiders Evil Plan
  • 巧妙利用树上结构,如可以用重链剖分的结构来快速定位:Nauuo and Binary Tree;若是多个数通过操作合并为一个数,可以思考操作的树形结构:Eternal Average;括号序列的树形结构是重要的:[省选联考 2022] 序列变换(差点因为这题没进队)

2.4 网络流

有一些入门的内容,不想整理了:网络流简单题选做网络流二十四题

把下面这些整理完之后,我才发现好像网络流确实已经很难有新意了,很多 \(\tt trick\) 都是反复出现的。

2.4.1 量的意义

  • 用流量的流入和流出代表加减,可以表示一些加减的不等式关系:Red-Blue Graph
  • 流量可以在基于要求的情况下,表示解决要求的途径,而费用可以看成途径的代价:Chips Challenge
  • 可以用路径来表达不合法的关系,再用最小割来获取最优解:Starry Night Camping老C的方块
  • 对于覆盖类型的限制,把需要覆盖的点串联起来,用路径表示覆盖的关系:奇怪的线段树

2.4.2 观察性质

  • 如果用网络流解决平面图问题,可以考虑黑白染色转二分图的性质:过山车
  • 网络流解决矩阵问题,可以用行列来建二分图:;但这有时候是个思维定式,如果行和列独立并且有其他限制,那么建单层图能更好地表达限制:Asa's Chess Problem
  • 完美匹配的等价条件是 \(\tt Hall\) 定理,所以如果原问题和 \(\tt Hall\) 有某种关联可以通过这层关系转化到网络流上:Construction of a tree
  • 拆分法,网络流一般只能解决单点对单点的限制,如果是多点对单点,那么大胆找结论,我们可以从答案的形式入手:Rainbow Triples;还有对代价的拆分,比如绝对值的微元贡献法:One Billion Shades of Grey
  • 如果某个问题可以建出其费用流模型,那么是有凸性的,就引申到了 \(\tt wqs\) 之类的算法:April Fools' Problem

2.4.3 小技巧

2.4.4 图匹配问题

  • 一般图匹配也许可以通过结论转化成二分图匹配(左部右部的匹配次数相同):模拟赛5-A
  • 一些情况下贪心地匹配:Add to Square(达到构造的界);模拟赛2-C(特殊的偏序关系)
  • 二分图的独立性(只需要考虑某一部的具体情况):Bipartite Blanket
  • 不能走回头路的博弈问题可以考察二分图匹配相关的结论,这是因为交错路具有特殊的数量关系:游戏
  • 经典问题:有向图求环划分,可以拆成入点和出点跑二分图匹配:

2.4.5 常见模型

  • 混合图的欧拉回路,思考清楚度数在原问题中对应着什么即可套用此模型:wait
  • 最大权闭合子图,可以解决带强制选取关系的选\(/\)不选问题,或者也可以解决类似的二选一问题:魔法商店
  • 最长反链,转最小链覆盖之后,用 \(\tt dfs\) 的方法构造即可:Birthday;也有构造新的偏序集再跑最长反链的题目:Making It Bipartite
  • 上下界网络流,可以表示一些强制限制:Showing Off带上下界的网络流

3.unknown

3.1 计数

3.1.1 问题转化

  • 映射法,遇到多对一的问题时(多种方案生成同构的结果),可以通过添加限制把多化一,构成双射:Two Histograms;可以根据数感,和常见的结构建立映射关系:神必的集合Slime and Sequences;遇到信息题时(确定未知变量),考虑我们都知道什么信息,和信息建立映射关系:Bears and Juice
  • 组合意义法,如果方案数是加权的,那么思考权值的组合意义,最好化为存粹的方案数:Min Product Sum教数学的校长;组合意义尽量合并多步计数(即把原来复杂的结果化为一个过程):;对于外层的枚举可以建立虚点来等效替换:数叶子;逆向应用一些定理也是组合意义的一个方向:无损加密
  • 把限制转化成单侧的,这样计数顺序会更明显:Centroid Probabilities
  • 切换计数对象,简化计数的主体:stairs;去除不易处理的限制:count;添加限制转化为容易计数的对象:Two Pieces

3.1.2 容斥/反演

  • 最常见的容斥方法是枚举不合法的个数:Two Histograms神经网络
  • 如果存在选取个数 \(\leq a_i\) 的限制,可以强制选取 \(a_i+1\) 个,然后记上 \(-1\) 的容斥系数:钥匙
  • \(\tt LGV\) 引理,原本求的是偶数逆序对的不交路径减去奇数逆序对的不交路径。在特殊的图中(比如网格图,数轴)可以直接求不交路径数量:无损加密,如果终点未知还可以考虑 \(dp\) 计算行列式:Random Robots
  • 容斥的另一种思考方向,先给出一种会算重的计数方法,然后找出这种计数方法算重的原因,然后对这个算重的原因容斥:;比如经典模型 \(\tt DAG\) 计数,就是容斥入度为 \(0\) 的点:Finding satisfactory solutions;类似的基环树计数,可以容斥叶子:人类补完计划
  • 集合划分容斥,用于解决相等关系的限制,直接对边数容斥即可:Distinct Multiples

3.1.3 统计方法

  • 思考答案的形式,然后思考在哪里统计,如果答案是区间则可以在端点处统计:Chords;如果答案是树上的点集,那么可以在其 \(\tt lca\) 处统计(写成代码就是在合并子树的时候统计):Vladislav and a Great Legend
  • 思考统计的顺序,确定合理的顺序可以让式子变得更简单,通常有偏序关系就意味着可能需要思考顺序:Inversions;分步统计,逐步确定的方法也是重要的:钥匙;为保证顺序,还可以在一次计数中结合不同的计数方法:模拟赛3-A;可以先确定一个大致的顺序,然后在转移时修正它:Square Constraints
  • 关于去重方法,可以考虑给同构的方案增加限制:Piling Up;比较无脑的去重方法,考虑一种方案会被计算多少次,然后用除法去重:Fox And Travelling;如果要考虑无序的子结构,可以考虑隔板法去重:Shake It!

3.1.4 常见模型

  • 卡塔兰数模型,可以解决在网格图中行走但是不越过某条直线的方案数:Ball Eat Chameleons
  • 斯特林数模型,可以在 \(n\)\(k\) 小的情况下优化计算 \(n^k\)Vladislav and a Great Legend
  • 本质不同字符串计数的问题,直接考虑建立 \(\tt DFA\)Strange Operation

3.1.5 概率期望

  • 注意利用等概率的性质,比如转等概率环,可以把总体的方案放到单点上去:Wine Thief、也可以方便地计算总方案数:AmShZ Farm
  • 如果题目保证了出现的概率,那么这题可能就是基于概率来寻找关键点:James and the Chase
  • 拆分。独立变量的概率常常可以拆分,这样可以分步解决问题:Strongly Connected Tournament;概率对期望的拆分十分重要,可以完成期望对概率的转化:Shuffles CardsGachapon
  • 概率期望类型的题目中,一些前缀 \(/\) 差分类型的转化往往能够简化问题:地震后的幻想乡

3.2 基础方法

3.2.1 势能法/均摊法

  • 适合势能法的题目有一些特征,比如覆盖问题:小Z与函数;染色问题:Intervals of Intervals亿块田(位运算可以看成数位的颜色段均摊);区间合并与分裂问题(通常是维护的东西具有单调性,可以把值相同的一段看成区间的题目):货币Holy Diver
  • 使用势能法时,可以从一些感性的角度,通过定义势能函数来入手:Souvenirs
  • 尽管有时候操作比较复杂,但是若是具有 某变量一定减少 的性质,就可以通过加速一些简单的过程来优化:Addition and Andition;可以通过一些简单的操作变换,使得减少量和花费的时间之间对应起来:五彩斑斓的世界
  • 势能线段树,可以维护区间取 \(\min\)、区间除法等操作:浅谈势能线段树在特殊区间问题上的应用Cartesian TreeStations
  • 均摊法最重要的是分析总体复杂度,所以一些暴力的操作可能看起来很慢但是总体复杂度优秀:Berland Miners

3.2.2 拆分法

使用拆分法时,最重要的是保证独立性。

  • 如果题目中存在时间顺序,可以把这个顺序破除来保证独立性(即换一个顺序计算):Addition and Andition
  • 可以对左右端点拆分来优化,比如应用到区间 \(dp\) 问题:Student's Camp;可以拆分之后分别计算:Cartesian Tree
  • 高维问题可以考虑拆分成独立的低维问题:Berserk RobotJumping sequence
  • 拆分法可以用来集中限制,比如把两个主体间的限制拆开,等效到一个主体上:Drazil and His Happy Friends;拆分法还可以分解限制,可以把区间限制拆开,分解到单点上:模拟赛2-B
  • 线段树可以理解成对二进制数位的拆分,有些题目可能利用线段树来拆分:Xor-Set

3.2.3 调整法

调整法的使用过程是:选取初始状态(Sergey's problem)、确定调整方式。

  • 有很多匹配问题具有神奇结论,证明可以考虑调整法:Modulo PairingBear and Cavalry
  • 如果某问题连判定合法性都困难,还要求你最优化的话,那么大胆使用调整法。从最优状态开始调整,使用最小代价来达成合法性(这样可以两个愿望一次满足):Two Faced CardsChips Challenge
  • 邓老师调整法,从一个合法状态开始,然后对它进行微调使得权值变大 \(/\) 变小:邓老师调整法Pastoral Oddities
  • 可以用调整法来研究最优解满足的性质,这时候使用一些简单的不等关系是重要的:遇到困难睡大觉转盘Max Correct Set
  • 两种决策的问题可以考虑主一副二的方法,先固定一个,然后用另一个调整以获得最优解:Squares
  • 连续型问题向离散型问题的转化,可以通过调整法证明只会取到端点值:Parametric MSTLevko and Game

3.2.4 分治法/倍增法

  • 矩形问题可以考虑交替分治,加上点双指针单调性什么的可以做到优秀复杂度:Empty Rectangles
  • 类似后缀数组的倍增技巧,优化的重点是充分利用上一层的信息:Minimal String Xoration月球列车
  • 使用倍增法的重要步骤是结合单次询问分析,找到关键的固定的可加速过程,然后倍增:麻烦的杂货店Hopping Around the Array
  • 倍增是基于二进制的,所以某些异或问题用倍增有奇效:温故而知新
  • 确定唯一的后继就可以倍增,可以认为地让这个后继满足一些优良性质:唱诗

3.2.5 神奇复杂度

3.2.6 根号相关

  • 总和一定时,注意种类 \(\sqrt n\) 的结论:Snowy MountainTree Degree Subset Sum
  • 值域分治。在位运算和四则运算混合时,预处理时先最大化前一半的数位,再最大化后一半的数位,预处理和询问平衡做到 \(O(n\sqrt n)\) 之类的复杂度:In a Trap;暴力前一半,状压后一半,可以做到 \(O(\sqrt n)\)进制转换;值域分块带有天然的偏序关系,在偏序关系限制比较严格的时候可以尝试使用:Set Merging
  • 根号分治。把种类按照出现次数分类已经是老生常谈了,但是注意分治后的情况下具有的性质:众数Huffman Coding on Segment;序列跳跃问题可以直接对后继的距离根号分治:Summer Oenothera Exhibition
  • 操作分块。结构变化且复杂的题目可以考虑每 \(O(\sqrt n)\) 个操作分成一块,分别处理。注意这样转化之后结构会变简单,可以把一些复杂的操作用暴力来实现:Jumping Through the Array

3.2.7 贡献法

贡献法最基础的用法就是改变和式的计算方式,使用贡献法时,首先确定贡献对象,然后思考这个对象在什么情况下会产生多大的贡献:Move by Prime

  • 多种情况下要统一贡献形式,可能需要钦定合适的贡献方式:钥匙(可以贪心匹配上的就贡献)
  • 基于大小关系比较的题目中,可以考虑使用 01-principle,即先考虑 \(01\) 序列的情况,再用贡献法推广:线段树

3.2.8 随机化

  • 扩大值域以减小出错概率。如果想通过行列式表示积和式的一些性质(比如是否为 \(0\)),那么可以扩大值域,直接计算行列式,出错的概率是极小的:亿些整理
  • 在出现频率差距较大时,随机抽样调查若干次可以获得想要的结果:Olha and Igor

3.2.9 枚举法

3.2.10 贪心法

  • 我们使用贪心时,尽可能要单一化贪心的对象,独立化贪心的代价。这需要我们观察代价的特点,使用拆分法对代价进行一些处理:[省选联考 2022] 序列变换;贪心对象多化一的处理:新年的腮雷

  • 统一代价的形式,这样更便于贪心的使用:Parametric MST;统一操作的形式,也便于贪心:Game RelicsEscape

  • 树上依赖贪心。如果存在先选父亲才能选儿子的限制时,弄出合并规则然后用堆维护:三角形牛半仙的魔塔

  • 如果代价具有凸性,那么可以会指向堆贪心之类的做法:WYR-Leveling Ground

3.3 数据结构

这里并不是对数据结构的系统总结,而是总结了一些有意思的思维点,可能对你做数据结构有帮助,但是前提还是有扎实的数据结构基础,能对任何结构信手拈来。

3.3.1 问题转化

  • 写出操作的线性变换形式,就可以直接套用矩阵:密码箱
  • 删除操作,可以看成回退到上一时刻,可以用保留所有历史版本的主席树来支持回退:火车管理
  • 对一段区间内的分段函数求和,可以对把自变量当成版本,以位置来建立主席树:Tower Defense
  • 对于强制在线的问题,可以先思考离线怎么处理,然后套上可持久化数据结构:区间第k小

3.3.2 考虑限制

  • 切换限制的主体。很多时候从题目的方向直接翻译是行不通的,这时候弄清限制涉及到了哪些对象,然后通过选取其他对象的形式来重新表述限制,就达到了切换限制主体的效果:铃原露露
  • 保留有效限制。限制之间也存在偏序关系,如果通过一些技巧可以达到排除无效限制的效果,那么就可能把限制的总量规约到一个较小的数量集。比如树上启发式合并来考虑和 \(\tt lca\) 有关的限制:铃原露露事情的相似度
  • 放宽限制。并不一定要在满足限制时检查,可以找维护一个合适的必要条件,把总检查次数限制在一定范围内:被创与地震
  • 收紧限制。对于限制较弱的问题,可以通过讨论特殊情况,使得要考虑的范围缩小:Path

3.3.3 确定维护对象

  • 尽量不要去维护有关特定值的信息,可以通过放宽条件的方式转化为维护最值:Bear and Bad Powers of 42Into Blocks
  • 可以通过切换主体的方式来确定维护对象。譬如有 \(A\rightarrow B\) 的影响,从 \(A\) 的角度看是一种效果,从 \(B\) 的角度看又是另一种效果。根据修改与询问的特性变换角度,可以确定最为合适的维护对象:The Tree;先弄清维护的信息是什么,然后切换主体,保持维护信息的不变即可:前进四诡异操作
  • 切换承载信息的主体,前提是原来的主体和新选取的主体之间可以建立对应关系:Nauuo and ODT;寻找决定性的对象,比如这个对象决定了答案,那么我们就尽力去描述它:区间和

3.3.4 思考如何维护

  • 如果难以对维护对象选取主元,那么考虑对称的维护两个对象:图论

  • 等效操作的思想是很重要的,当你切换维护对象之后,可以通过等效操作来适应现在所维护的东西:The Tree数轴变换

  • 整体标记法。思考清楚整体标记对于单点的影响即可:Latin Square

  • 注意维护信息的顺序,比如有的问题只适合以一种顺序加入:Julia the snail

3.3.5 常见模型

  • 递归半边模型。其本质是离线与在线的结合,利用维护好的信息每次可以将考虑的区间折半。维护括号匹配:Nastya and CBS;维护极长上升子序列类的信息:转盘
  • 染色模型。一些类区间赋值类操作可以向染色模型转化:轻重边;区间求并的问题,可以扫描线加染色模型,也就是维护最晚被染的颜色:rrusq区间本质不同子串个数
  • 猫树分治。主要作用是提供一个分治中点,比如可以把分治中点当成历史最大值的起点:rprmq1
  • 二进制分组。可以支持末尾的在线加入,搬到线段树上可以支持末尾删除和区间查询:Unknown
posted @ 2021-08-10 22:53  C202044zxy  阅读(18454)  评论(31编辑  收藏  举报