HDU1423 最长公共上升子序列LCIS
Problem Description
This is a problem from ZOJ 2432.To make it easyer,you just need output the length of the subsequence.
Input
Each sequence is described with M - its length (1 <= M <= 500) and M integer numbers Ai (-2^31 <= Ai < 2^31) - the sequence itself.
Output
output print L - the length of the greatest common increasing subsequence of both sequences.
Sample Input
1 5 1 4 2 5 -12 4 -12 1 2 4
Sample Output
2
Source
Recommend
lcy
分析:经典的LCIS问题,用dp求解,既然问题是LIS+LCS,那么状态转移方程肯定是结合了这两道题的。观察一下这两道题的方程有啥特点LIS中的状态是以某一位结尾的,LCS中的表示到第几位,那么LCIS就要把这两个特点结合起来,一维表示到第几位,一维表示以某一位结尾,那么设f[i][j]表示a中前i个和b中前j个的LCIS,并且以b[j]结尾,显然如果a[i] != b[j],那么f[i][j] = f[i-1][j],否则f[i][j] = max{f[i-1][k]} (1 <= k < j && b[k] < b[j]),三重循环,复杂度要爆表了.
考虑一下能不能只用两重循环,找最大值的部分,我们要找到b[k] < b[j]的最大值f[i-1][k],我们能不能不枚举k呢?注意到我们每次枚举j的时候都是重复找了最大值的,如果a[i] > b[k]了,就更新最大值,因为我们要用最大值来更新a[i] = b[k]的情况,既然a[i]都大于b[k]了,那么自然b[k] < b[k'],因为都是顺序枚举的,保证都会更新到.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int inf = 0x7ffffff; int t,l1,l2,a[510],b[510],f[510][510],ans,maxx; int main() { scanf("%d",&t); while (t--) { memset(f,0,sizeof(f)); ans = 0; scanf("%d",&l1); for (int i = 1; i <= l1; i++) scanf("%d",&a[i]); scanf("%d",&l2); for (int i = 1; i <= l2; i++) scanf("%d",&b[i]); for (int i = 1; i <= l1; i++) { maxx = 0; for (int j = 1; j <= l2; j++) { f[i][j] = f[i - 1][j]; if (a[i] > b[j]) maxx = max(maxx,f[i-1][j]); if (a[i] == b[j]) f[i][j] = maxx + 1; } } for (int i = 1; i <= l2; i++) ans = max(ans,f[l1][i]); if (t != 0) printf("%d\n\n",ans); else printf("%d\n",ans); } return 0; }