题解LCIS

Posted kcn999

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解LCIS相关的知识,希望对你有一定的参考价值。

题目描述

  给定两个整数序列,写一个程序求它们的最长上升公共子序列。

 

输入格式

  每个序列用两行表示,第一行是长度L,第二行是该序列。

输出格式

  在第一行,输出该LCIS的长度。第二行,输出该LCIS。

 

输入样例

5

1 4 2 5 -12

4

-12 1 2 4

 

输出样例

2

1 4

 

题解

  表面上看起来是个$O(n^4)$,但实际上可以优化到$O(n^2)$(貌似还可以用树状数组优化到$O(nlogn)$)

  我们设$dp[i][j]$为以$a_1$到$a_i$中的一个数和$b_j$为结尾的LCIS,容易得到$dp[i][j] = \underset1 \leqslant k < jmax \left \ dp[j - 1][k] + 1 \right \$。

  其实我们可以在枚举$i$、$j$的时候顺便维护$\underset1 \leqslant k < jmax \left \ dp[j - 1][k] + 1 \right \$,这样就把时间复杂度降到$O(n^2)$了。

  观察方程,其实我们第一位只会用到$i - 1$和$i$,这里又可以用滚动数组优化。

技术图片
#include <iostream>

#define MAX_N (500 + 5)
#define MAX_M (500 + 5)

using namespace std;

int n, m;
int a[MAX_N], b[MAX_M];
int dp[MAX_M];
int p[MAX_M];
int ans;

void LCIS(int x)

    if(p[x]) LCIS(p[x]);
    cout << b[x] << " ";
    return;


int main()

    cin >> n;
    for(register int i = 1; i <= n; ++i)
    
        cin >> a[i];
    
    cin >> m;
    for(register int i = 1; i <= m; ++i)
    
        cin >> b[i];
    
    int pos = 0, tmp;
    for(register int i = 1; i <= n; ++i)
    
        tmp = 0;
        for(register int j = 1; j <= m; ++j)
        
            if(a[i] > b[j] && dp[j] > dp[tmp]) tmp = j;
               if(a[i] == b[j])
            
                dp[j] = dp[tmp] + 1;
                p[j] = tmp;
            
        
    
    for(register int i = 1; i <= m; ++i)
    
        if(dp[i] > dp[pos]) pos = i;
    
    cout << dp[pos] << "\n";
    if(dp[pos]) LCIS(pos);
    return 0;    
参考程序

 

以上是关于题解LCIS的主要内容,如果未能解决你的问题,请参考以下文章

TYVJ1071 LCIS 线性DP+决策集优化

POJ 4718 /// 树链剖分+线段树区间合并 求树上两点间的LCIS长度

poj2127——LCIS

[HDOJ3308]LCIS(线段树,区间合并,新的代码)

HDU 5904 LCIS (DP)

HDU 3308 LCIS (经典区间合并)线段树