动态规划&记忆化搜索
基础模板
最长上升子序列1
模板题,定义 \(dp_i\) 表示以 \(i\) 结尾的 LIS 长度。
code
最长上升子序列2
数据范围变大了。思路后面补。
code
最长上升子序列3
叫你输出序列。
定义 \(pre_i\) 表示让 \(dp_i\) 最大的 上一个数的编号。
判断里面加一句:\(pre[i]=j\)。
最长公共子序列1
\(dp[i][j]\) 表示字符串 \(x\) 前 \(i\) 个和字符串 \(y\) 前 \(j\) 个的 LCS。
- 若 \(x[i]=y[j]\) ,\(dp[i][j]=dp[i-1][j-1]+1\).
- 否则:\(dp[i][j]=\max (dp[i-1][j],dp[i][j-1])\).
最长公共子序列2
关于为什么可以转化成 LIS 问题,这里提供一个解释。
A:3 2 1 4 5
B:1 2 3 4 5
我们不妨给它们重新标个号:把 \(3\) 标成a,把 \(2\) 标成b,把 \(1\) 标成c……于是变成:
A: a b c d e
B: c b a d e
这样标号之后,LCS 长度显然不会改变。但是出现了一个性质:
- 两个序列的子序列,一定是 A 的子序列。而 A 本身就是单调递增的。因此这个子序列是单调递增的。
换句话说,只要这个子序列在B中单调递增,它就是A的子序列。
哪个最长呢?当然是B的 LIS 最长。
所以只需要 \(O(n\log n)\) 求一个 LIS 即可。(具体见最长上升子序列2)