总结 2026.3.21
计数类 DP
按数值 DP
即考虑每个数真实的值。
题目 1
一个长度为 \(n\) 的序列,要求第 \(i\) 个数在 \(L_i\sim R_i\) 范围内,且序列不降。
这时候记录数值的好处就体现出来了。
\(dp_{i,j}\):第 \(i\) 个数值为 \(j\) 的方案数。
\[dp_{i,j}=\sum_{k=L_{i-1}}^{k\le j,h\le R_{i-1}}dp_{i-1,k}
\]
题目 2
一个长度为 \(n\) 的序列,要求第 \(i\) 个数在 \(L_i\sim R_i\) 范围内,且相邻元素之差不超过 \(K\)。
考虑状压。
状压哪些数被用过了,而被用过数的总数就是当前填的位置。
还需要记录上一个用的是哪个数,相差过大就不行。
按排名 DP
考虑值的好处是什么?就是你可以直观地得到当前的值。
比如:要求当前值与上一个值相差不大于 \(K\),此时维护值就有用。
题目 1
定义前缀最大值为大于其前面所有元素的元素,求 \(n\) 的排列中前缀最大值数量为 \(k\) 的数量。
考虑用 \(dp_{i,j}\) 表示前 \(i\) 个位置,有 \(j\) 个前缀最大值。
如何转移?
前 \(i\) 个数自然会产生排名 \(1\sim i\),若当前填入的数排名为 1,则会成为前缀最大值,否则不会。
\[dp_{i,j}=dp_{i-1,j-1}+dp_{i-1,j}\times(j-1)
\]
题目 2
给定一个字符串 \(s\),包含 > 和 <,若 \(s_i\) 为 小于,则 \(a_i<a_{i+1}\),否则反之。求有多少种满足条件的 \(n\) 的排列 \(a\)。
用 \(dp_{i,j}\) 表示第 \(i\) 个数填的是前 \(i\) 个数中排名为 \(j\) 的数。
<
若当前数排名为 \(j\),且需要前面的数小于他,则前面的数的排名只能是 \(1\sim j-1\)。
\[dp_{i,j}=\sum_{k=1}^{j}dp_{i-1,k}
\]
>
若当前数排名为 \(j\),且前面的数要大于他,则前面数排名可以是前 \(i-1\) 个数中的 \(j\sim i-1\)。为什么可以取 \(j\)?若第 \(i\) 个数小于前面的第 \(j\) 个数,则在前 \(i\) 个数中,前面那个数的排名会变成 \(j+1\),还是大于当前数。
\[dp_{i,j}=\sum_{k=j}^{i-1}dp_{i-1,k}
\]
为什么这里不能用具体值来做?因为具体的值可能会出现重复!而题目要求的是排列!
所以用值 DP 的缺陷就暴露出来了。
用排名 DP 更加灵活,加入一个数之后只需变一下前面的排名,不用考虑重复的问题。
浙公网安备 33010602011771号