求两个串的最长公共上升子序列。
题目描述This problem differs from one which was on the online contest.
The sequence a1,a2,...,an is called increasing, if ai<ai+1 for i<n .
The sequence s1,s2,...,sk is called the subsequence of the sequence a1,a2,...,an , if there exist such a set of indexes 1<=i1<i2<...<ik<=n that aij=sj . In other words, the sequence s s s can be derived from the sequence a a a by crossing out some elements.
You are given two seque��ñ,����nces of integer numbers. You are to find their longest common increasing subsequence, i.e. an increasing sequence of maximum length that is the subsequence of both sequences.
输入输出格式输入格式:
The first line contains an integer n n n ( 1<=n<=500 ) — the length of the first sequence. The second line contains n n n space-separated integers from the range [0,109] — elements of the first sequence. The third line contains an integer m m m ( 1<=m<=500) — the length of the second sequence. The fourth line contains m m m space-separated integers from the range [0,109] — elements of the second sequence.
输出格式:
In the first line output k — the length of the longest common increasing subsequence. In the second line output the subsequence itself. Separate the elements with a space. If there are several solutions, output any.
输入输出样例输入样例#1:
72 3 1 6 5 4 641 3 5 6
输出样例#1:
33 5 6
输入样例#2:
51 2 0 2 131 0 1
输出样例#2:
20 1
Solution:
本题线性DP。
直接把两个常见的dp揉合,定义状态$f[i][j]$表示匹配到$A$串第$i$位并以$B$串第$j$位结尾的LCIS长度。
那么不难得到状态转移方程:$f[i][j]=max(f[i-1][k]+1),a[i]==b[j]\&\&a[i]>b[k]$。
显然可以滚掉第一维,然后若直接转移复杂度是$n^3$的,我们可以优化掉枚举决策$k$的循环,在状态转移完后存下最大的满足条件的$f[k]$作为下次转移的决策,显然满足最优性,这样的时间复杂度是$O(n^2)$的。
输出方案就只需要在转移时顺带记录下$b$串每个位置的$pre$就好了。
代码:
/*Code by 520 -- 10.20*/#include#define il inline#define ll long long#define RE register#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)using namespace std;const int N=505;int n,a[N],m,b[N],f[N],pre[N];int stk[N],top,ans;int main(){ scanf("%d",&n); For(i,1,n) scanf("%d",a+i); scanf("%d",&m); For(i,1,m) scanf("%d",b+i); For(i,1,n) { int pos=0; For(j,1,m){ if(a[i]==b[j]) f[j]=f[pos]+1,pre[j]=pos; if(a[i]>b[j]&&f[pos]<f[j]) pos=j; } } int pos=0; For(i,1,m) if(f[i]>f[pos]) pos=i; printf("%d\n",f[pos]); while(f[pos]--) stk[++top]=b[pos],pos=pre[pos]; while(top) printf("%d ",stk[top--]); return 0;}