序列dp
序列dp
最长不下降子序列
我们都会 \(O(n^2)\) 的做法,这里讲的是 \(O(n\ log\ n)\) 的做法。
依旧是求 \(f(i)\) 表示以 \(A_i\) 为结尾的最长不下降子序列的长度。
但我们不再是通过枚举去找到一个最优的 \(A_j \le A_i\),而是维护一些信息直接 \(O(1)\) 判断以 \(A_i\) 为结尾的最长不下降子序列能否为 \(l\) 。
这里利用了一点贪心的思想,维护一个数组 \(d\),\(d_l\) 表示考虑 \(1\) 到 \(i - 1\) 时,所以长度为 \(k\) 的不下降子序列末尾元素的值最小为多少。
若 \(A_i \ge d_{l-1}\),则以 \(A_i\) 为结尾的最长不下降子序列长度至少为 \(l + 1\)。
不难理解 \(d\) 数组满足 \(d_i \le d_{i + 1}\)。
所以可以通过二分找到最大的满足 \(A_i \ge d_{l - 1}\) 的 \(l\),即为 \(f(i)\)。
时间复杂度 \(O(n\ log\ n)\)。
最长公共子序列
我们都会 \(O(nm)\) 的做法。但特殊的情况下,可以做到 \(O(n\ log\ n)\)。
那就是两个序列的元素在对面具有唯一对应的元素。
一个简单的例子就是求两个排列的最长公共子序列。
求 \(3, 1, 4, 2, 5\) 和 \(1, 4, 3, 2, 5\) 的最长公共子序列,等价于求 \(1, 2, 3, 4, 5\) 和 \(2, 3, 1, 4, 5\) 的最长公共子序列,而后者等价于求 \(2, 3, 1, 4, 5\) 的最长上升子序列。
题面:
给定两个长度分别为 \(n, m\) 且仅由小写字母构成的字符串 \(A\),\(B\)。
求 \(A\),\(B\) 的最长公共子序列。
\(n \le 10^6\),\(m \le 10^3\)
分析:
显然 \(O(nm)\) 无法通过,而且也没有前面提到的性质。怎么办呢?
两个序列的长度很不对称,这一点值得关注。
这时候就需要用到之前提到的技巧,将 dp 的值和状态进行交换。
显然最终答案不会超过较短的序列的长度,也就是不超过 \(m\)。
而 LCS 满足一定的单调性,即 \(A[1, i]\) 与 \(B[1, j]\) 的最长公共子序列长度一定不小于 \(A[1, k]\) 与 \(B[1, j]\) 的最长公共子序列长度。
故设状态 \(f(i, j)\) 为:\(A\) 与 \(B\) 前 \(i\) 位的最长公共子序列长度为 \(j\) 的前缀最短是多少(即朴素算法的答案与第一维状态对调)。
预处理 \(A\) 的每一位的下一个 \(a, b, ···, z\) 的出现位置即可 \(O(1)\) 转移。
复杂度 \(O(m^2 + 26n)\),可以通过本题。
RaucousRockers演唱组
用 \(g(i, j, k)\) 表示前 \(i\) 首歌,用 \(j\) 张唱片加 \(k\) 分钟,最多可包含的歌曲数。
当 \(k \ge l_i\) 时:
当 \(k < l_i\) 时:
\(g(i, j, k) = max\{g(i - 1, j - 1, t - l_i), g(i - 1, j, k)\}\)
时间复杂度 \(O(nmt)\)。
还可以再优化一下吗?
\(g(i, j) = (a, b)\) 表示前 \(i\) 首歌曲中选 \(j\) 首最少需要:\(a\) 张唱片+\(b\) 分钟。
其中 \((a, b) + l_i = (a’, b’)\) 定义为:
- 当 \(b + l_i \le t\) 时:\(a' = a, b' = b + l_i\)。
- 当 \(b + l_i > t\) 时:\(a' = a + 1, b' = l_i\)。
题目所求的是:\(max(k | g(n, k) \le (m - 1, t))\)。
时间复杂度 \(O(n^2)\)。

浙公网安备 33010602011771号