熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。
小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。
小沐沐说,对于两个数列 A 和 B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。
奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。
不过,只要告诉奶牛它的长度就可以了。
数列 A 和 B 的长度均不超过 3000。
第一行包含一个整数 N,表示数列 A,B 的长度。
第二行包含 N 个整数,表示数列 A。
第三行包含 N 个整数,表示数列 B。
输出一个整数,表示最长公共上升子序列的长度。
1≤N≤3000,序列中的数字均不超过 231−1。
- 4
- 2 2 1 3
- 2 1 2 3
2
(DP,线性DP,前缀和) O(n2)
这道题目是AcWing 895. 最长上升子序列和AcWing 897. 最长公共子序列的结合版,在状态表示和状态计算上都是融合了这两道题目的方法。状态表示:
f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合;
f[i][j]的值等于该集合的子序列中长度的最大值;
状态计算(对应集合划分):首先依据公共子序列中是否包含a[i],将f[i][j]所代表的集合划分成两个不重不漏的子集:
不包含a[i]的子集,最大值是f[i - 1][j];
包含a[i]的子集,将这个子集继续划分,依据是子序列的倒数第二个元素在b[]中是哪个数:
子序列只包含b[j]一个数,长度是1;
子序列的倒数第二个数是b[1]的集合,最大长度是f[i - 1][1] + 1;
…
子序列的倒数第二个数是b[j - 1]的集合,最大长度是f[i - 1][j - 1] + 1;
如果直接按上述思路实现,需要三重循环:作者:yxc
链接:https://www.acwing.com/solution/content/4955/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- for (int i = 1; i <= n; i ++ )
- {
- for (int j = 1; j <= n; j ++ )
- {
- f[i][j] = f[i - 1][j];
- if (a[i] == b[j])
- {
- int maxv = 1;
- for (int k = 1; k < j; k ++ )
- if (a[i] > b[k])
- maxv = max(maxv, f[i - 1][k] + 1);
- f[i][j] = max(f[i][j], maxv);
- }
- }
- }
-
- 作者:yxc
- 链接:https://www.acwing.com/solution/content/4955/
- 来源:AcWing
- 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
优化后将三重循环压缩成两成层循环
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- using namespace std;
- typedef long long LL;
- const int N = 3e3 + 5;
- int n;
- int a[N], b[N],f[N][N];
-
- int main() {
- scanf("%d", &n);
- for (int i = 1; i <= n; i++) {
- scanf("%d", &a[i]);
- }
- for (int i = 1; i <= n; i++) {
- scanf("%d", &b[i]);
- }
- for (int i = 1; i <= n; i++) {
- int maxv = 1;
- for (int j = 1; j <= n; j++) {
- f[i][j] = f[i - 1][j];
- if (a[i] == b[j]) {
- f[i][j] = max(f[i][j], maxv);
- }
- if (a[i] > b[j])
- maxv = max(maxv, f[i - 1][j]+1);
- }
- }
- int ans = 0;
- for (int i = 1; i <= n; i++) {
- ans = max(ans, f[n][i]);
- }
- cout << ans << endl;
- return 0;
- }
-
-
-