一些不容易想到的解法技巧

DPair

2020-07-08 10:00:03

Personal

**本博客同步发布于我的[个人博客](https://dpair.gitee.io/articles/tricks)** 1、贪心的反悔机制(可撤销贪心) 2、模拟题倒着离线模拟一遍,和添加、删除有关的都可以考虑倒着走。信息不对称的题倒着搜。 3、$C_{x+y}^{x}$可以表示坐标轴上从$(0,0)$走到$(x,y)$ 4、$ gcd(x, y)=gcd(x-y,y)=gcd(x~mod~y,y) $ 5、 设 $d(x)$ 为 $x$ 的约数个数 $$ d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1] $$ 6、两段区间的平方和如果相同可以认为这两段区间相同,立方和则更加稳妥。 由于容易被卡,我现在一般用五次方和或哈希。 7、二分可将一个最优化问题转化为一个判定问题。当然这个最优化也可能是题目里面的人在最优化。其实不只是最优化问题,容易判定一个答案是否为正解且单调的都可以二分。 8、分层图(等其他分类的模型)建立虚点。 9、DFS序维护子树。 10、前缀优化建图(eg.[P6378](https://www.luogu.com.cn/problem/P6378))、线段树优化建图(连续区间)。 11、log级别的转移可以用矩阵乘法,不一定是非要$O(1)$推式子。 12、遇见式子可以尝试化简,或者直接写出能得出答案的式子,然后强拆,也许会发现可以斜率优化或者各种其他优化的神奇结论。 13、方向性的题目考虑建图,当然关系性的题目也可能与图论有些关系(比如差分约束或2-SAT) 14、最优化问题优先考虑能否去除无用条件,比如图论题目中删去不可能经过的无用边。或找到一些可以贪心的性质,使得答案保证正确性的情况下少考虑很多情况。 15、对于一道你不会做的题,考虑什么特殊情况下它可做,然后通过二分等技巧把该问题转化成你会做的问题。比如考虑一道题中的部分分。 16、图论题正推比较困难的话,考虑建反图反推一遍?似乎有些期望的题目就要这么做? 17、折半搜索似乎是个好东西,$2^n$能硬生生优化成$2^{(n/2)}$这样子的,主体算是分治。 18、位运算有关的先考虑01-Trie,或者按位考虑**贪心**,及其**可行性**,一般来说看起来能贪心的都有策略,只不过你没想到。 19、DP设状态关心数据范围,也许有一些你根本想不到的状态设计方法是可行的(比如什么四维数组)。 20、期望也许可以直接表示出来 21、DP题基本思路:设计状态,分析初始状态、终结状态,设计状态转移、优化 \*22、转化考虑本质,或者说找不变量,比如区间修改往往和前缀和或差分有关,有可能一段区间的变化就变成了单点的变化。 23、连续区间前缀和优化 24、计数问题考虑容斥 \*25、正难则反,比如“存在”的判断就挺难的,可以反着来转化成“任意”。 26、期望DP考虑每一种情况及其概率及其贡献,说不定DP方程就出来了。 27、计数问题不一定是数学题,也可能是递推或者DP。 \*28、多去思考思考题目到底要我们求什么,或者说我们求的东西到底是什么,到底等价于什么,搞不好就把问题转化成了一个能做的问题。 29、对于一些有限制的题目,可以考虑不断更改题目给出的状态直到得到一种不被限制影响的状态以直接得出答案,比如启发式合并。 30、有句老话说得好:你不会做的题很有可能就是 $DP$ 31、最优化题目尝试寻找题目中隐藏的单调性,或者寻找这道题**在什么条件下**满足单调性。 32、似乎博弈论很多都是结论题,并且涉及到分类讨论,如果发现一个结论被证伪了,先不要着急,仔细想一想这个结论在什么情况下为伪,然后继续分类讨论,搞不好乱搞下去就 $AC$ 了。 33、构造最优解题或贪心题考虑答案的限制,并想办法证明限制的充分性与必要性,如果能证出来那么直接在限制里去最大值就可以了。 34、有个东西叫根号分治,有个东西叫记忆化。同一个问题 $>\sqrt{n}$ 的解常常有一些美妙的性质,可以考虑分治一下。 35、期望DP的时候经常会涉及到那一项它自己,可以考虑涉及到自己时的意义。 36、不要被表面现象所迷惑,比如期望也不一定是小数,有可能就是整数。 \*37、对于一道显然不可做的题目,看看它有什么特殊要求,比如数据结构题中查询操作很少,或者操作有特殊要求,或者数据范围有很明显的导向性。 38、一个问题如果很明显的分成了两部分,说不定不是同一个算法,不要被坑了。比如有些题的前半部分操作是数据结构,后半部分其实是一个 $O(1)$ 水题,但你受前半部分影响会认为这是一道 $log_2(n)$ 的题,然后你就想不出来了。(eg.[P3948](https://www.luogu.com.cn/problem/P3948)) 39、曼哈顿距离和切比雪夫距离可以互相转化,很多时候给你曼哈顿往往正解需要切比雪夫。所以一个想不出来不妨想一想另一个。 40、图论题不仅可以考虑点,也可以尝试考虑边。 41、时间轴也能分块哒? 42、询问太多,离线存不下?考虑一下分组离线。 \*43、对于题目内容包含操作(不仅仅是毒瘤数据结构)的题目,考虑操作的本质,并进一步分析操作本质的性质,而不是仅仅考虑完操作的本质就结束了。 44、很多无解的题目都满足“当且仅当……的时候无解”,可以考虑优先判断这个。 45、又有乘除又有加减的答案很不好处理,考虑化成同一种运算。 46、莫队不好处理多个区间的问题,可以考虑拆成多个询问。然而有些时候多个区间之间有关联,即答案的更新需要两个区间同时处理,此时考虑进行转化使得两个区间不需要同时处理,或者把两个区间直接变成一个区间。 47、有些题目数据范围是假的。比如说表面上告诉你某一个数的范围是多少多少,但实际上真正对答案有贡献的(甚至于说可行的)数据范围只有一点点而已。适用于题目很接近正解了,但数据范围不对的时候,可以考虑缩减范围。 48、务必关注数据范围,有些 **变量之间** 可能会存在优美的关系。 49、有时DP中某一状态的一个自变量与另一个自变量存在函数关系,此时就可以压缩一维。 50、空间不够,$map$ 来凑。 51、与连通块、强连通分量、双联通分量有关的优先考虑缩点,看缩点后的图有什么优美的性质,有时可能只需要用上缩点的思想,不需要真的缩点,搞不好也能发现问题的本质。 52、和最值有关的问题不妨考虑一下单调栈。 53、有些题目的单调性是分段的,例如 **对于由同一个决策点转移过来的所有决策点单调** ,或者满足 **对于所有奇数单调,对于所有偶数单调** 然后就可以利用这个单调性完成优化。 53、$10^{18}$ 或 $10^9$ 这种范围可能是推式子也可能是矩阵乘法,但不要忘了有个东西叫二分。 54、和奇偶有关的也可以考虑二进制。 55、判断多次操作能否达到某一个解时,可以先找出每一次操作中不变的变化量(有点像差分),然后就可以快速判断可行性了。 56、题面中可以把点分成多类(甚至可能很牵强)的图论题可以考虑染色,然后考虑染色后的图有什么性质。也可以考虑将其分为几个集合,然后分析集合内部的性质与集合之间的性质。 57、博弈论题目优先考虑影响胜负的因素,此时可能会出现多个影响胜负的因素,如果出现这种情况,可以考虑先判断有没有 **只要有这个因素,就一定必胜** 的情况出现,如果有,那么后面的博弈过程可能就可以变成 **双方都在要求/避免这种情况的出现**。也许就可以消除一个因素。 58、对于基于一串数列的、类似 $Nim$ 的这种博弈,可以考虑从 $n=1$ 的情况去优先考虑,当然有些时候这种是不适用的,可以改为从全局去考虑。 59、有些矩阵乘法的题目可能需要特定的方程才能进行矩阵优化,比如你可能瞎搞搞出来了一个 $O(nm)$ 的 $DP$ 但要完成 $O(log_mn^3)$ 的矩阵乘法可能反而需要 $O(n^2m)$ 的 $DP$。 60、有些问你是否满足条件的题目考虑 **最劣情况** 会何时满足条件,搞不好你会发现这个 **最劣情况** 其实挺小的。 61、计数题可以考虑计算每一个点的贡献,或者考虑定一部分指针快速求出另一部分指针,或者进行 $DP$ 配合上容斥,甚至可能直接得出结论。 62、网络流拆点使得一个点只被用一次。 63、树上问题考虑方向:按点分类,按边分类,按子树分类,按子树大小分类,按子树大小奇偶性分类。 64、如果难以考虑贡献,考虑反贡献即破坏。 65、时刻记住最短路的特点->两边之和大于等于第三边。 66、构造可以考虑分类讨论,有时需要特判,甚至不需要知道为什么当且仅当某一情况下无解。比如发现若 $n=x$ 可以构造出一切 $n=x+2$ 的情况,就可以分奇偶讨论。 67、你怕不是没考虑过倍增,尤其是变化多的时候,很可能需要 $log$ 级的或多或少与倍增有关的东西。 68、线段树上多维护一些值也许可以通过优秀的 $pushup$ 操作实现各种区间问题。 常见的比如区间右往左、左往右、中间这三个值。 69、找转化本质的一个方法,列出来所有你能想到的变量(甚至是答案),然后转化一次,看什么变了,什么没变。 70、对于一切两种状态的,优先考虑 $2-SAT$ 或者二进制什么的,当然可撤销贪心也在考虑范围内。 71、$n=20$ 且显然不能暴搜的自动状压。 72、提到合并就可以去想启发式合并了。 73、正难则反不一定是完全容斥或者证方面,也可以是换一种思路的侧面,或者说换一个第一关键字。 74、前驱后继 -> 链表、平衡树(set)。 75、数形结合不仅限于斜率优化,看着像几何问题的东西就可以直接上。 76、绝对值自动分类讨论。 77、启发式分裂???(草) 78、养成看样例说明的好习惯,防止读错题。 79、DP时考虑开两个数组,相辅相成。这个思路适用于1个数组难以转移,且题目基本显然是DP的情况。可以从另一角度追加一个数组,但又与第一个数组有所关联。 80、随机化拥有很优秀的效率,有时不妨试一试,有可能正确性也不会低到哪里去。因为有些题目中,随机化次数只要足够大,错误概率是指数级的低。 81、值域分块:配合两种操作次数差异非常悬殊时用于平衡复杂度的一种思想(——_Wallace_) 82、分块适合处理不满足区间可加性的问题。 83、操作和除法有关系的似乎都有一些优秀的性质(~~来自东方的神秘力量~~),比如可以根号分块、或者均摊复杂度带log。 84、优化的几种思路:无用的操作不予处理、可以合并的一起处理。 85、启发式合并一类的似乎都是优化暴力?把 $n$ 通过一些显然到不能再显然的结论处理成均摊 $log$ ? 86、线段树不仅能在修改、pushup等操作上做文章,也可以在查询上做文章以保证复杂度。 87、DS题里面的换根很可能是假的,可以根据根与点的位置关系分类讨论。例如换根为 $root$ 后 $LCA(u,v)$ 为 $LCA(u, v), LCA(u, root), LCA(v, root)$ 中深度最大的一个。(eg.[CF916E](https://www.luogu.com.cn/problem/CF916E)) 88、第 $k$ 小似乎都与二分有一些关系?哦不好意思,似乎与大小有关的都可以考虑考虑二分。 comment:“值域分块+暴跳 表示不服( ” —— [Peal_Frog](https://www.luogu.com.cn/user/44805) 89、去重常用离线算法。 90、线段树合并的两种方式:一种是不新开节点,破坏另一棵树的结构并直接把另一棵树合并到当前树上,以节省空间;另一种是新开节点,优势是不会破坏树的结构可以在线,但是空间很容易炸。 91、合并时可能有很多种返回值,也可能没有返回值。然而这个返回值的灵活运用很重要。 92、交互题考虑一部分询问干什么,另一部分询问干什么。 93、想到明显优于时空限制的算法也不要怕,很有可能你也是对的并且爆踩了标算。 94、符合条件的期望×总方案数也可以算出总符合条件的方案数。 95、消除限制的几种思路:把限制设置到状态中、容斥、一次性达到限制的上界。 96、问题转化不一定是 “操作的本质是什么”, 也可以是 “出现一种情况的充分必要条件是什么”。比如问你 “可能有多少种不同的结果”,就可以考虑 “这种结果的充分必要条件” ,然后统计 “这种条件的出现次数”。 97、遇到没见过的题目先分析性质!性质!性质!看看他到底要你干什么! 98、同一种操作也许不同的处理方式也对应着不同的选择。 99、二分判定时考虑给大于某个数的数标号,小于某个数的数标另一个号。 100、同一道题涉及到多个范围时,考虑小的范围能否推出大的范围,并尽可能考虑到所有范围。 101、有时化简为繁反而可以得到出乎意料的效果。 102、一些 $O(n^2)$ 显然可做但数据范围不允许的有关区间的题目,可以考虑将数据状态量化成一个个权值,使得后面每一个点都可以快速查询前面满足条件的权值数。 103、数据随机也许会影响算法效率。 104、看到和方案有关的东西了?那你还是得考虑一下DP的,哪怕它披着数据结构或者其他什么东西的衣服。 105、总方案数 $2^n$ 种并且每一种互不相同的 DP 题(其实也就是每一个操作可以选也可以不选问你所有方案的权值之和这种题),可以考虑对于每一个贡献计算产生贡献的概率,最后乘上一个方案数就是答案。 106、对于构造题,可以考虑合法的构造满足的条件有什么性质,然后直接乱搞即可。 107、看到“能”马上想“不能” 108、线段树+递推=线段树维护矩阵乘法 109、有矛盾?(~~一斤鸭梨!~~)考虑带权并查集。 110、解决选一堆数的问题时一种常用的思路:考虑每一个单独的数的贡献,可行性问题考虑贡献的上下界,计数性问题考虑贡献具体的量。 111、可离线的区间查询问题可以考虑先排序一个端点,然后把另一个端点弄成单点查询。 112、括号匹配中未匹配的必然是 **总括号个数-(左边不匹配的+右边不匹配的)** 113、去重可以考虑维护使得任何时刻每一个数值都只有一个产生贡献。 114、淀粉树套路(摘自第一篇题解):对于每个点,开一个数据结构 $S1$ 存储点分树子树的贡献,再开一个数据结构 $S2$ 存储点分树父亲的贡献,用来容斥,防止算重。 115、构造题直接大力猜想,然后尝试证明或者给反例。比如可以尝试升序排序、降序排序什么的,然后暴力去猜。很快啊!你就可以做出来了。 116、让你同时求 $1\to k$ 的所有答案的题目,一般答案之间有所关联,或者可以顺便求出。 117、分块的每一次操作都可以重构散块,只要复杂度是 $O(\sqrt{n})$ 一个块就行。 118、合并两个线性基可以暴力把一个线性基中的所有元素拿出来 $\text{insert}$ 到另一个当中。(~~这单纯是因为我不会线性基~~) 119、对于数组 $a$ 与其差分异或和数组 $b$ ,$a_{[l,r]}$ 与 $a_l\cup b_{[l+1,r]}$ 的线性基是相等的。 120、查找一个元素可以考虑用一些东西进行索引,比如找区间可以左端点开 $\text{set}$ 存右端点,找因数可以根据因数建 $\text{set}$ 存倍数。 121、操作也可以分块(有点类似回滚莫队?) 122、分块题优先考虑暴力怎么做,然后考虑预处理什么东西,反正分块本质上也就是优雅的暴力 123、“大于、小于”有关的题可以考虑用 0/1 表示 124、一般 “最优化数对” 的题目都是先搞出个 $O(n^2)$ 的解法然后看看有什么性质。 ——摘自Owen_codeisking的题解 125、一个序列必然可以被表示成多个单调段,不妨往这方面想想。 126、区间排序其实是有通解的。。。可以用线段树合并、线段树分裂以及类似珂朵莉树的写法维护单调段,然后就可以方便地通过线段树合并完成区间排序。 127、区间数颜色的一个套路:对于每一个位置,维护其下一个同色点的位置 $nxt$,那么显然我们只需要求一段区间内 $nxt > r$ 的点的个数即可。 128、如果DS题中有一些询问奇奇怪怪的,很不可维护的样子,然后又是让你判断对错,看看是不是满足“区间长度大于/小于某个数时必然有/无解”这样的性质。一种常见的思路是假设这个区间有/无解,那么它会满足一些什么性质。 129、交互题只要概率够就认为它可做,不一定要 $100\%$ 正确。 130、网络流题发现建不出模就大力拆点,拆一个不够就拆两个,拆两个不够就拆 $n$ 个,只要数据范围允许,拆多少都行。 131、**最大流=最小割** 中似乎不能根据是否满流来判断一条边是否被割。。。似乎要通过分层中是否有层来判断。 132、矩阵方格有关考虑黑白染色和网络流。 133、网络流流一遍不够判断就再换个源汇流一遍。 134、网络流题中“一对多”不代表不能用网络流,可以采用把序列变成一条链,然后超源超汇建在链首和链尾的方式建图。 135、单点修改比区间修改至少好做100倍。 136、时刻记住期望的线性性!!! 137、不要随便加各种奇奇怪怪的剪枝。 138、对于一道最优化题考虑它的下界以及下界是否可以达到,常用方法是考虑不变量。 139、同时和两个数有关的式子尽可能化成只和一个数有关的式子。