做题技巧及寄巧
多手玩几组样例总能发现一些性质的。
dp部分
状态设计
-
树形dp状态设计时珂以多想:以i为根的子树中怎么怎么样时的最值答案。
-
有时候dp状态设计可以不直接表示答案所求值,而是将答案所求设计在阶段条件中(即数组下标)。一般是求解答案的过程中有多个变量需要注意,如P1273
-
有时候状态直接设答案所求不太方便转移时,珂以先另设一个辅助dp数组,把这个辅助数组求出来之后再进行dp。其实这个辅助数组的求法也就是dp,如P4158
-
dp状态设计尽量贴近题面,题面中和转移相关的信息尽量都涵盖在状态表示和对应之中。
-
初始化的时候要想到转移的时候哪里有可能越界并且给他补上去,或者转移顺序和范围就严格设好。
-
遇到状态巨大,转移空间时间耗费巨大的题珂以先从最基本的状态开始想,然后一步一步优化,把数组一维一维滚掉,虽然一般这种题都非常智慧。
-
我们在做有消耗条件的dp时设计的状态一般都是还剩下多少个物品而不是用了多少个物品,这是我们关心的而且方便转移。
-
对于一些给出你前后数的一些约束条件,让你求方案数的题,可以考虑设状态为当枚举到第几个位置时并且这个位置是 时的方案数,如这个
-
对于树形dp,当题设条件依赖树的具体形态时珂以考虑:设状态为一个点与父亲/儿子之间关系的各种情况时的求值,如 P8595
转移、维护技巧
-
有时候复杂一点的问题珂以先求解简单的问题,把答案求出来之后再去求解原本的问题,如UVA1437。
-
二维平面上的dp珂以考虑用二维前缀和维护。
-
遇到这种需要dp的东西的状态是不确定的,要求我们记录方案数的情况时(比如求所有子串中合法的什么什么串的个数),珂以考虑对状态进行分类讨论,用尽量简洁并且能转移的分类来概括状态。
-
换根dp转移时对于一个节点的子树珂以考虑和他的次小/大的什么东西转移,可以是次小链/子树/重儿子这样的。
-
遇到基环树dp可以考虑把多出来的那条边当作一个额外的限制条件,然后正常地dp,之后比较一下那条边的两个点各自为起点的答案,如P1453&P2607
-
遇到转移的范围不确定的时候我们珂以先将基本思路的代码写下来,然后计算题目大概给我们留下的时间复杂度,然后去猜测这个dp取值的范围,如P2851
-
多头讲的:有些题能很简单写出一个复杂度高的转移式,考虑贪心地去考虑哪些状态是能保证不会被其他更优的状态所代替,再去转移这些保证最优的状态,如CF1768F。这种区间转移问题珂以固定左端点并固定两端点的大小关系然后不断拓展区间来判断值得转移的区间。
数据结构
-
动态开点,先不建树,在update里加一条:
if(!now) now=++cnt;
字符串
-
KMP匹配的时候一些操作珂以考虑往回跳 数组来实现,像 这样的。
-
对于求区间哈希值:设左端点为 右端点为 ,哈希值就是
(a[r]-a[l-1]*b[r-l+1]%mod+mod)%mod
, 数组时哈希值前缀和, 是对于不同区间长度的底数 -
寄巧:KMP预处理 数组时 不要从 开始循环,从 开始
for(int i=2;i<=n;++i)