复制粘贴的:
通过一个外层的 DP 来计算使得另一个 DP 方程最终结果为特定值的输入数。
例如求有多少种输入使得一个背包 DP 恰好答案为 K K 。
外层 DP 的状态是所有子 DP 的状态的值。
子 DP 状态数很少,通常经过滚动数组优化,比如 3 n 3 n 变成 2 × 3 2 × 3 )
通常我们有技巧地枚举子 DP 的输入,比如逐位考虑输入。
由于我们只对 DP 方程的最终结果感兴趣,我们并不需要记录子 DP 的输入数据,只需要记录转移以后,DP 每个状态的值就可以了。
例:BZOJ3864
题目大意:
给定字符串 S S 与正整数 m m ,你需要对每个 i = 0 , ⋯ , | S | i = 0 , ⋯ , | S | 求出:
有多少个长为 m m 的字符串 T T 使得 LCS ( S , T ) LCS ( S , T ) 长度为 i i 。LCS LCS 指最长公共子序列。
1 ≤ m ≤ 1000 , 1 ≤ | S | ≤ 15 1 ≤ m ≤ 1000 , 1 ≤ | S | ≤ 15 。
回忆 LCS LCS 的 DP: f ( i , j ) f ( i , j ) 表示 S [ 1 ⋯ i ] , T [ 1 ⋯ j ] S [ 1 ⋯ i ] , T [ 1 ⋯ j ] 的 LCS 长度,有转移:
f ( i , j ) = { f ( i − 1 , j − 1 ) + 1 , S [ i ] = T [ j ] max ( f ( i − 1 , j ) , f ( i , j − 1 ) ) , S [ i ] ≠ T [ j ] f ( i , j ) = { f ( i − 1 , j − 1 ) + 1 , S [ i ] = T [ j ] max ( f ( i − 1 , j ) , f ( i , j − 1 ) ) , S [ i ] ≠ T [ j ]
我们应当记录的是,目前长度为 i i ,且和 S S 的 LCS 是某个数组的字符串数量。
注意到这个转移之和上一行相关,因此只需要记录最后一行,即对每个 f ( ⋅ , j ) f ( ⋅ , j ) 的所有状态,都记录下来。暴力记录需要 O ( | S | | S | ) O ( | S | | S | ) 个状态,注意到差分数组只会是 0 , 1 0 , 1 ,因此考虑记录差分数组,即可做到 O ( 2 | S | ) O ( 2 | S | ) 。用 O ( | Σ | × | S | 2 | S | ) O ( | Σ | × | S | 2 | S | ) 时间预处理所有状态的后继,总的时间复杂度为 O ( ( m + | S | ) 2 | S | × | Σ | ) O ( ( m + | S | ) 2 | S | × | Σ | ) 。
附送简单题 游园会 ,记录末尾是不是 N,NO 即可。
试看看!
我觉得大标题后紧跟小标题很不好看,因此我要在这里加一行字。
dp of dp 套一层数位 DP。不难想到枚举 i = 1 , ⋯ , n i = 1 , ⋯ , n 算贡献。
考虑怎么算最长公共子串,设 f ( i , j ) f ( i , j ) 表示两个串 s , t s , t 以 s i , t j s i , t j 结尾的最长公共子串,那么
f ( i , j ) = { f ( i − 1 , j − 1 ) + 1 , s i = t j 0 , s i ≠ t j f ( i , j ) = { f ( i − 1 , j − 1 ) + 1 , s i = t j 0 , s i ≠ t j
我曾一度以为状态数应当是 5 4 = 625 5 4 = 625 ,但注意到 f ( i , j ) ≤ min ( i , j ) f ( i , j ) ≤ min ( i , j ) ,因此状态数不超过 2 × 3 × 4 × 5 = 120 2 × 3 × 4 × 5 = 120 。由于这个只代表某两个位置结尾的最长公共子串,还要记录全局 f f 的最大值。
额,但是算出来是 n × lg m × | Σ | × lg n × 120 × 2 × 2 × ≥ 4 × 10 9 n × lg m × | Σ | × lg n × 120 × 2 × 2 × ≥ 4 × 10 9 ,有点恐怖!不过 CYJ 说能过
另一种做法:枚举之后把每个后缀插入 acam,标记一下每个点在 trie 上的深度,记录一下当前走过路径上的 maxdep 即可。复杂度是 O ( n | Σ | lg n lg m ) O ( n | Σ | lg n lg m ) 。
额我也不知道这题算不算 dp of dp
不难发现剩下的数必然是 n n ,考虑对一个排列怎么算次数:建出笛卡尔树,发现只要一个节点的左子树或者右子树被删空了,那么它就会被删除。在笛卡尔树上 DP,设 f u f u 表示删空 u u 子树需要的次数,则当 u u 不在左右边缘时 f u = max ( f lson ( u ) , f rson ( u ) , min ( f lson ( u ) , f rson ( u ) ) + 1 ) f u = max ( f lson ( u ) , f rson ( u ) , min ( f lson ( u ) , f rson ( u ) ) + 1 ) ,否则 f u = f lson/rson ( u ) + 1 f u = f lson/rson ( u ) + 1 。
现在要计数有多少个排列的笛卡尔树能够使得 f root = k f root = k 。发现 f f 的转移式中 max max 取到第三种情况当且仅当 f lson ( u ) = f rson ( u ) f lson ( u ) = f rson ( u ) ,因此设 F ( i , j ) F ( i , j ) 表示 1 ⋯ i 1 ⋯ i 的排列,最终 f root = j f root = j 的方案数;转移时枚举最大值的位置,有
F ( x , j 0 ) × F ( y , j 1 ) × ( x + y + 1 x ) → F ( x + y + 1 , max ( j 0 , j 1 , min ( j 0 , j 1 ) + 1 ) ) F ( x , j 0 ) × F ( y , j 1 ) × ( x + y + 1 x ) → F ( x + y + 1 , max ( j 0 , j 1 , min ( j 0 , j 1 ) + 1 ) )
然后是一个很厉害的结论,注意到删除次数不超过 O ( log n ) O ( log n ) (由于一个序列至多有一半的数是极大值),因此暴力转移就是 O ( n 2 log 2 n ) O ( n 2 log 2 n ) ,前缀和优化一下可以 O ( n 2 log n ) O ( n 2 log n ) 。
由于 u u 在最左侧时转移式不同,因此需要多记录 G ( i , j ) G ( i , j ) 表示 i i 在最左侧的方案数。
LOJ3724
有个暴力:f ( u , x , y ) f ( u , x , y ) 表示给以 u u 为根的子树填数,选 u u 时的最大权独立集大小为 x x ,不选 u u 时为 y y 的方案数。转移就直接写一下树上最大权独立集那个 DP,有
f ( u , x 1 , y 1 ) × f ( v , x 2 , y 2 ) → f ( u , x 1 + y 2 , y 1 + max ( x 2 , y 2 ) ) f ( u , x 1 , y 1 ) × f ( v , x 2 , y 2 ) → f ( u , x 1 + y 2 , y 1 + max ( x 2 , y 2 ) )
发现复杂度是 O ( n 3 k 4 ) O ( n 3 k 4 ) 。
然后发现,当 x ≤ y x ≤ y 的时候记录 x x 没有意义,若 x > y x > y ,那么 x − y ≤ k x − y ≤ k 。因此可以记录 f ( u , j , y ) f ( u , j , y ) 表示以 u u 为根的子树填数,选 u u 时的最大权独立集大小为 y + j y + j (j > 0 j > 0 ) 或者 ≤ j ≤ j (j = 0 j = 0 ),不选 u u 时为 y y 的方案数。转移式类似:
f ( u , j 1 , y 1 ) × f ( v , j 2 , y 2 ) → f ( u , max ( 0 , j 1 − j 2 ) , y 1 + y 2 + j 2 ) f ( u , j 1 , y 1 ) × f ( v , j 2 , y 2 ) → f ( u , max ( 0 , j 1 − j 2 ) , y 1 + y 2 + j 2 )
复杂度 O ( n 2 k 4 ) O ( n 2 k 4 ) 。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!