【题解】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,容易得到当$a_{i} = b_{j}$时,$dp[i][j] = \underset{1 \leqslant k < j}{max} \left \{ dp[i - 1][k] + 1 \right \}$,否则$dp[i][j] = dp[i - 1][j]$。

  其实我们可以在枚举$i$、$j$的时候顺便维护$\underset{1 \leqslant k < j}{max} \left \{ dp[i - 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;    
}
参考程序

 

转载于:https://www.cnblogs.com/kcn999/p/10960562.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值