什么是最长公共上升子序列(bushi)
最长公共上升子序列就是最长的公共的上升的子序列(子序列不需要连续哦)
解决 想法 显然考虑dp, $ dp_{i,j} $ 表示选取序列 a 的前 i 个元素, lcis以 $ b_i $ 结尾的最长公共子序列的长度
状态转移方程
$ a_i \neq b_i $ : $ dp_{i, j} \gets dp_{i - 1, j} $ //如果 $ a_i \neq b_i $ , 那么在以 $ b_i $ 结尾的公共子序列中一定不选 $ a_i $
$ a_i = b_i $ : $ dp_{i, j} \gets max(dp_{i - 1, k}), k < j $ ////如果 $ b_k $小于 $ b_j $, 那么便可由 $ b_k $ 转移, 注意 $ a_i $ 已经和 $ b_i $ 配对所以不考虑
附上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <bits/stdc++.h> using namespace std;#define ll long long #define maxn 100020 #define rep(i, a, b) for(int i = (a); i <= (b); i ++) #define love return #define you 0 int dp[5001 ][5001 ];int a[maxn], b[maxn];signed main () { freopen ("a.in" , "r" , stdin); freopen ("a.out" , "w" , stdout); int n, m; cin >> n; rep (i, 1 , n) cin >> a[i]; cin >> m; rep (j, 1 , m) cin >> b[j]; rep (i, 1 , n) { rep (j, 1 , m) { dp[i][j] = dp[i - 1 ][j]; if (a[i] == b[j]) { int mx = 0 ; rep (k, 1 , j - 1 ) { if (b[k] < b[j]) { mx = max (mx, dp[i - 1 ][k]); } } mx += 1 ; dp[i][j] = mx; } } } int ans = 0 ; rep (i, 1 , m) ans = max (ans, dp[n][i]); cout << ans << endl; love you; }
优化 但考虑到最坏情况下复杂度会退化到 $ O(n^3) $, 所以有没有什么方案可以再进一步降低复杂度呢?
我们可以发现 $ a_i = b_j, b_j > b_k $ 和 $ a_i > b_j $ 是等价的.
所以在第二层循环中只需要记一个 mxdp 来维护当前 $ dp_{i, j} 的最大值就好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <bits/stdc++.h> using namespace std;#define ll long long #define maxn 100020 #define rep(i, a, b) for(int i = (a); i <= (b); i ++) #define love return #define you 0 int dp[5001 ][5001 ];int a[maxn], b[maxn];signed main () { freopen ("a.in" , "r" , stdin); freopen ("a.out" , "w" , stdout); int n, m; cin >> n; rep (i, 1 , n) cin >> a[i]; cin >> m; rep (j, 1 , m) cin >> b[j]; rep (i, 1 , n) { int mx = 0 ; rep (j, 1 , m) { dp[i][j] = dp[i - 1 ][j]; if (a[i] > b[j]) mx = max (mx, dp[i][j]); if (a[i] == b[j]) dp[i][j] = mx + 1 ; } } int ans = 0 ; rep (i, 1 , m) ans = max (ans, dp[n][i]); cout << ans << endl; love you; }
显然还可以使用滚动数组优化空间, 但滚动数组我不想写
寄