AcWing 272. 最长公共上升子序列
原题链接
中等
作者:
ITNXD
,
2021-04-19 22:17:55
,
所有人可见
,
阅读 357
详细请看注释!包括等价变形!
参考代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 3010;
int n, a[N], b[N], f[N][N];
/*
状态表示:f[i][j]表示以a序列的前i个和b序列的前j个构成的,且以b[j]结尾的公共上升子序列的集合!--> 求其最大值!
前半个条件:最长公共子序列
后半个条件:最长上升子序列
状态计算:
1. 不包含a[i]:f[i][j] = f[i - 1][j]
2. 包含a[i]:(当然是在a[i] == b[j]才成立)
以最长上升子序列思路分析,找倒数第二个点:
即可以 以b[1] ~ b[j - 1]结尾集合来划分,当然得满足b[k] < b[j]:k 属于 [1, j - 1]
即:f[i][j] = max(f[i][j], f[i - 1][k] + 1);
时间复杂度:n^3
对代码做等价变形,将时间复杂度优化到n^2:
*/
int main(){
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++) cin >> b[i];
// for(int i = 1; i <= n; i ++)
// for(int j = 1; j <= n; j ++){
// // 1. 不包含a[i]
// f[i][j] = f[i - 1][j];
// // 2. 当a[i] == b[j]时,包含a[i]
// if(a[i] == b[j]){
// // 最小是1
// f[i][j] = max(f[i][j], 1);
// for(int k = 1; k < j; k ++)
// if(b[k] < b[j])
// f[i][j] = max(f[i][j], f[i - 1][k] + 1);
// }
// }
for(int i = 1; i <= n; i ++){
int maxv = 1;
for(int j = 1; j <= n; j ++){
// 1. 不包含a[i]
f[i][j] = f[i - 1][j];
// 2. 当a[i] == b[j]时,包含a[i]
// 代码变形1:a[i]b[j]相等时再进行更新
if(a[i] == b[j]) f[i][j] = max(f[i][j], maxv);
// 代码变形2:b[j] < a[i]时进行迭代式更新b[j]之前(只有a[i] == b[j]才有意义),即a[i]之前的f[i - 1][j] + 1的最大值
if(b[j] < a[i]) maxv = max(maxv, f[i - 1][j] + 1);
}
}
int res = 0;
for(int i = 1; i <= n; i ++) res = max(res, f[n][i]);
cout << res << endl;
return 0;
}