Codevs 2185 最长公共上升子序列 LCIS

22 篇文章 0 订阅

Codevs 2185 最长公共上升子序列

定义状态 dp[i][j] 表示以 a 串的前 i 个字符 b 串的前 j 个字符且以 b[j] 为结尾构成的LCIS的长度。

n^3
状态转移方程:
dp[i][j] = dp[i-1][j] (a[i] != b[j])
dp[i][j] = max(dp[i-1][k]+1) (1 <= k <= j-1 && b[j] > b[k] && a[i] == b[j])

分析:
1.对于 a[i] != b[j] 的情况, 因为我们要求的序列是 公共的, 所以 a[i] 对已 包含 b[j] 的 LCIS 无贡献。
2.当 a[i] == b[j] 时, 我们需要在满足 可以 以b[j] 为结尾的 的子序列中选一个最长的, 容易想到, 在我们已经处理过的 dp[i-1][k] (1 <= k <= j-1)中, 为什么呢? 因为 当前 a[i] 是我们正在处理的, 不能算处理过的, 所以是 i-1,为什么不是 i-2 , i-3 呢? 因为 i-1 肯定不会比 i-2, i-3 差。至于第二维,我们就需要枚举了,枚举的时候需要保证 b[k] 是小于 b[j] 的。

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
using namespace std;

#define MAXN (3030)
int a[MAXN], b[MAXN];
int dp[MAXN][MAXN];

int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    for(int j = 1; j <= n; ++ j) scanf("%d", &b[j]);

    for(int i = 1; i <= n; ++ i)
    {
        for(int j = 1; j <= n; ++ j)
        {   
            if(a[i] != b[j]) dp[i][j] = dp[i-1][j];
            else if(a[i] == b[j])
            {
                int MAX = 0; 
                for(int k = 1; k < j; ++ k)
                if(b[j] > b[k])
                    MAX = max(MAX, dp[i-1][k]);
                dp[i][j] = MAX+1;
            }
        }
    }

    int ans = 0;
    for(int j = 1; j <= n; ++ j)
        ans = max(ans, dp[n][j]);
    cout << ans << endl; 
    return 0;
}

n^2

n^3 的算法 我们的时间浪费在了 第3层 for 上, 前2层 是必须的啊。
所以我们想到, 在更新dp 的时候 我们可以维护一下 MAX 的值, 因为 a[i] == b[j] 时 b[k] 的贡献 是b[k] < b[j] 的, 所以 等同于 b[k] < a[i] 的, 因为 a[i] 的循环在最外面, 所以我们完全可以更新 在 a[i] == b[j] 时用到的 MAX。

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
using namespace std;

#define MAXN (3030)
int a[MAXN], b[MAXN];
int dp[MAXN][MAXN];

int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
    for(int j = 1; j <= n; ++ j) scanf("%d", &b[j]);

    for(int i = 1; i <= n; ++ i)
    {
        int MAX = 0;
        for(int j = 1; j <= n; ++ j)
        {   
            dp[i][j] = dp[i-1][j];
            if(a[i] > b[j]) MAX = max(MAX, dp[i][j]);
            else if(a[i] == b[j]) dp[i][j] = MAX+1;
        }
    }

    int ans = 0;
    for(int j = 1; j <= n; ++ j)
        ans = max(ans, dp[n][j]);
    cout << ans << endl; 
    return 0;
}

福利样例

输入数据
10
1 5 3 6 3 2 7 3 6 2 
9 6 2 3 1 5 3 3 6 1

正确答案
3

然而! Codevs 上实测 10个数据点, n^2 比 n^3 慢 50ms。。

LCIS 还可以优化空间,这里就不再说了。

资料文件:http://blog.csdn.net/wall_f/article/details/8279733
http://wenku.baidu.com/view/3e78f223aaea998fcc220ea0.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值