Codeforces[10D] LCIS 【最长公共上升子序列】

Description

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 can be derived from the sequence a by crossing out some elements.

You are given two sequences 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.

Input 

The first line contains an integer n (1 ≤ n ≤ 500) — the length of the first sequence. The second line contains n space-separated integers from the range [0, 10^9] — elements of the first sequence. The third line contains an integer m (1 ≤ m ≤ 500) — the length of the second sequence. The fourth line contains m space-separated integers from the range [0, 10^9] — elements of the second sequence.

Output 

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.

Examples

input

7
2 3 1 6 5 4 6
4
1 3 5 6

output

3
3 5 6  

 input

5
1 2 0 2 1
3
1 0 1

 output

2
0 1 

题目大意:

给定长度小于等于 500 的数组 A,B,求他们的最长公共上升子序列。 

分析:

dp[i,j] 表示 A_1...A_i 与 B_1...B_j 可以构成的以 B_j 为结尾的LCIS的长度。

当 A_i \neq B_j 时,有 dp[i,j]=dp[i-1,j]

当 A_i = B_j 时,有 dp[i,j]=\max_{0\leq k< j,B_k<B_j}(dp[i-1,k])+1

这里因为枚举 k,O(n^3) 会超时,所以进行优化。

记录 [0,j)中所有 B_k<B_j 中 dp[i-1,k] 的最大值,直接拿来查询,那么我们把 i 作为最外层的循环,不停维护这个最大值,然后就可以把时间复杂度降到 O(n^2)

具体解释见代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 500 + 5;

int dp[maxn][maxn],p[maxn][maxn];
int a[maxn],b[maxn];
vector<int> v;
int n,m,ans,path;

void LCIS(int a[],int n,int b[],int m){
    for(int i=1;i<=n;i++){//外层循环
        int maxlen=0,pre=0;//maxlen代表dp[i-1][k]中的最大值,pre代表当前maxlen下的前一个B序列中选出的值(记录路径)
        for(int j=1;j<=m;j++){
            //这里假设Ai和Bj不等
            dp[i][j]=dp[i-1][j];
            p[i][j]=p[i-1][j];
            if(a[i]==b[j]&&dp[i][j]<maxlen+1){//更新dp[i][j]和p[i][j]
                dp[i][j]=maxlen+1;
                p[i][j]=pre;
            }
            if(b[j]<a[i]&&dp[i-1][j]>maxlen){//更新maxlen和pre
                maxlen=dp[i-1][j];
                pre=j;
            }
        }
    }
}

void Print(int pa) {//打印路径
    if(!pa) return;
    Print(p[n][pa]);
    cout<<b[pa]<<" ";
}

int main() {
    memset(dp,0,sizeof(dp));
    memset(p,0,sizeof(p));
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d",&b[i]);
    }
    LCIS(a,n,b,m);
    //选出最长路径
    for(int i=1;i<=m;i++){
        if(ans<dp[n][i]){
            ans=dp[n][i];
            path=i;
        }
    }
    printf("%d\n",ans);
    Print(path);
    return 0;
}
发布了30 篇原创文章 · 获赞 5 · 访问量 900

猜你喜欢

转载自blog.csdn.net/qq_42840665/article/details/104055450