题意
给定两个字符串 a,b,求 a,b 的最长公共上升子序列
暴力
参考最长公共子序列的做法,设计 dp 状态为 dpi,j 表示匹配到 ai 时以 bj 结尾的最长公共上升子序列
考虑转移:
- 当 ai=bj 时,显然有 dpi,j=dpi−1,j
- 当 ai=bj 时,显然有 dpi,j=1≤k<j, bk<bjmin(dpi−1,k)
暴力转移的时间复杂度为 O(n3)
考虑优化 ai=bj 时的转移
因为 ai=bj,上式显然等价于 dpi,j=1≤k<j, bk<aimin(dpi−1,k)
那么对于每一个 i ,转移时所需要的决策集合是只增不减的,我们可以在转移的同时维护决策集合(中的最优方案),这样转移只需 O(1) 判断即可
可以发现 dpi,j 只会从 k<j 的地方转移过来,所以我们还可以使用滚动数组优化
那么最后的转移方程即为
dpj=min(dpj,val+1), val=1≤k<j, bk<aimin(dpk)
代码
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
| #include <bits/stdc++.h> namespace solution { typedef long long LL; const int MAXN = 3000 + 5; int n; int ans = 0; int max[MAXN]; int dp[MAXN]; int s1[MAXN], s2[MAXN]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &s1[i]); } for (int i = 1; i <= n; i++) { scanf("%d", &s2[i]); } for (int i = 1; i <= n; i++) { int val = 0; for (int j = 1; j <= n; j++) { if (s1[i] == s2[j]) { dp[j] = std::max(dp[j], val + 1); } if (s2[j] < s1[i]) { val = std::max(val, dp[j]); } ans = std::max(ans, dp[j]); } } printf("%d\n", ans); return 0; } } int main() { solution::main(); return 0; }
|