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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章