关于 dp 套 dp 的一些思考--zhengjun
dp 套 dp 一般有三种形式:
-
暴力搜出一种东西的状态,发现数量不大,建出自动机开始跑;
-
有关字符串的匹配问题,例如 kmp 或 AC 自动机上;
-
有关 LIS/LCS 问题的可以使用一种特殊的内层 dp 优化状态。
前两个没什么好讲的,讲一下第三个。
LIS
记 \(f_i\) 为 \(1\sim i\) 的 LIS 长度(不一定要 \(i\) 结尾)。
发现 \(f_i\le f_{i+1}\),同时也有 \(f_{i+1}-1\le f_i\)。
所以 \(f_{i+1}-f_i\in\{0,1\}\),于是可以状态压缩这个差分数组。
但是这样子做需要从小到大加数,每次在加的位置改为 \(1\),后面第一个 \(1\) 变成 \(0\)(如果没有就不管)。
这样可以把 LIS 压缩成 \(2^n\)。
例题
HHHOJ #1255. 「NOIP 2023 模拟赛 20230716 D」拳击比赛 加强版
直接这么压缩 LIS,复杂度 \(O(nm4^n)\) 无法通过。
发现每一位一次填数的时候,如果填数的集合为 \(S\),dp 的差分数组为 \(1\) 的集合为 \(T\)。
那么有 \(T\subset S\),所以状态数实际上是 \(O(3^n)\),而且有很多状态其实也是无效的。
时间复杂度 \(O(nm3^n)\),看似 \(1e9\) 无法通过,实际上加个非零剪枝就可以做到 1s 以内。
LCS
LCS 和 LIS 是差不多的。
设 \(f_i\) 为 \(s_{1\sim i}\) 与目标串的 LCS。
显然也有 \(f_i\le f_{i+1},f_{i+1}\le f_i +1\)。
还是状压 \(f_{i+1}-f_i\in \{0,1\}\),每次加入一个字符的时候,预处理后继状态即可。
例题
就是这么压缩 LCS 就行了。