HDU 1423 && ZOJ 2432 (LCIS模板)

来源:互联网 发布:双十一每年数据 编辑:程序博客网 时间:2024/05/18 01:01


定义状态

F[i][j]表示以a串的前i个整数与b串的前j个整数且以b[j]为结尾构成的LCIS的长度。

状态转移方程:

①F[i][j] = F[i-1][j] (a[i] != b[j])

②F[i][j] = max(F[i-1][k]+1) (1 <= k <= j-1 && b[j] > b[k])

现在我们来说为什么会是这样的状态转移方程呢?

对于①,因为F[i][j]是以b[j]为结尾的LCIS,如果F[i][j]>0那么就说明a[1]..a[i]中必然有一个整数a[k]等于b[j],因为a[k]!=a[i],那么a[i]对F[i][j]没有贡献,于是我们不考虑它照样能得出F[i][j]的最优值。所以在a[i]!=b[j]的情况下必然有F[i][j]=F[i-1][j]。

对于②,前提是a[i] == b[j],我们需要去找一个最长的且能让b[j]接在其末尾的LCIS。之前最长的LCIS在哪呢?首先我们要去找的F数组的第一维必然是i-1。因为i已经拿去和b[j]配对去了,不能用了。并且也不能是i-2,因为i-1必然比i-2更优。第二维呢?那就需要枚举b[1]...b[j-1]了,因为你不知道这里面哪个最长且哪个小于b[j]。这里还有一个问题,可不可能不配对呢?也就是在a[i]==b[j]的情况下,需不需要考虑F[i][j]=F[i-1][j]的决策呢?答案是不需要。因为如果b[j]不和a[i]配对,那就是和之前的a[1]...a[j-1]配对(假设F[i-1][j]>0,等于0不考虑),这样必然没有和a[i]配对优越。(为什么必然呢?因为b[j]和a[i]配对之后的转移是max(F[i-1][k])+1,而和之前的i`配对则是max(F[i`-1][k])+1。


以上的代码的时间复杂度是O(n^3),那我们怎么去优化呢?通过思考发现,第三层循环找最大值是否可以优化呢?我们能否直接把枚举最大的f[i-1][k]值直接算出来呢?假设存在这么一个序列a[i] == b[j],我们继续看状态转移方程②,会发现b[j] > b[k],即当a[i] == b[j]时,可以推出a[i] > b[k],那么有了这个表达式我们可以做什么呢?可以发现,我们可以维护一个MAX值来储存最大的f[i-1][k]值。即只要有a[i] > a[j]的地方,那么我们就可以更新最大值,所以,当a[i] == b[j]的时候,f[i][j] = MAX+1,即可


可以发现,其实上面的代码有些地方与0/1背包很相似,即每次用到的只是上一层循环用到的值,即f[i-1][j],那么我们可以像优化0/1背包问题利用滚动数组来优化空间。如果是求最长公共下降子序列呢?很明显嘛,把状态定义改动一下,即f[i][j]表示以a串的前i个整数与b串的前j个整数且以b[j]为结尾构成的LCDS的长度,具体实现的时候只要把a[i] > b[j]改为a[i] < b[j]就可以啦。

Greatest Common Increasing Subsequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8249    Accepted Submission(s): 2666


Problem Description
This is a problem from ZOJ 2432.To make it easyer,you just need output the length of the subsequence.
 

Input
Each sequence is described with M - its length (1 <= M <= 500) and M integer numbers Ai (-2^31 <= Ai < 2^31) - the sequence itself.
 

Output
output print L - the length of the greatest common increasing subsequence of both sequences.
 

Sample Input
151 4 2 5 -124-12 1 2 4
 

Sample Output
2
 

Source
ACM暑期集训队练习赛(二)
 

Recommend
lcy
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 5e2 + 5;int dp[maxn], a[maxn], b[maxn], n, m;int main(){    int t;    cin >> t;    while(t--)    {        memset(dp, 0, sizeof(dp));        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]);        for(int i = 1; i <= n; i++)        {            int maxx = 0;            for(int j = 1; j <= m; j++)            {                if(a[i] > b[j]) maxx = max(maxx, dp[j]);                if(a[i] == b[j]) dp[j] = maxx + 1;            }        }        int ans = 0;        for(int i = 1; i <= m; i++)            ans = max(ans, dp[i]);        if(t != 0)            printf("%d\n\n", ans);        else            printf("%d\n", ans);    }    return 0;}



Greatest Common Increasing Subsequence

Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge

You are given two sequences of integer numbers. Write a program to determine their common increasing subsequence of maximal 
possible length.

Sequence S1, S2, ..., SN of length N is called an increasing subsequence of a sequence A1, A2, ..., AM of length M if there exist 1 <= i1 < i2 < ...< iN <= M such that Sj = Aij for all 1 <= j <= N, and Sj < Sj+1 for all 1 <= j < N. 


Input

Each sequence is described with M - its length (1 <= M <= 500) and M integer numbers Ai (-2^31 <= Ai < 2^31) - the sequence itself.


Output

On the first line of the output print L - the length of the greatest common increasing subsequence of both sequences. On the second line print the subsequence itself. If there are several possible answers, output any of them.


This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.


Sample Input

1

5
1 4 2 5 -12
4
-12 1 2 4


Sample Output

2
1 4


Source: Northeastern Europe 2003, Northern Subregion
Submit    Status
记录路径

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int maxn = 505;int n, m, t, a[maxn], b[maxn], dp[maxn][maxn], pathx[maxn][maxn], pathy[maxn][maxn], cur, ans;void Printf(int x, int y){    if(dp[x][y] == 0)        return;    if(pathx[x][y] != -1 && pathy[x][y] != -1)    {        int tx = pathx[x][y];        int ty = pathy[x][y];        Printf(tx, ty);        if(dp[x][y] != dp[tx][ty] && y != 0)        {            cur++;            if(cur < ans)                printf("%d ", b[y]);            else                printf("%d\n", b[y]);        }    }}int main(){    cin >> t;    while(t--)    {        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]);        memset(dp, 0, sizeof(dp));        memset(pathx, -1, sizeof(pathx));        memset(pathy, -1, sizeof(pathy));        int tmpx = 0, tmpy = 0;        for(int i = 1; i <= n; i++)        {            tmpx = 0, tmpy = 0;            int maxx = 0;            for(int j = 1; j <= m; j++)            {                dp[i][j] = dp[i-1][j];                pathx[i][j] = i-1;                pathy[i][j] = j;                if(a[i] > b[j] && maxx < dp[i-1][j]) maxx = dp[i-1][j], tmpx = i-1, tmpy = j;                if(a[i] == b[j]) dp[i][j] = maxx+1, pathx[i][j] = tmpx, pathy[i][j] = tmpy;            }        }        ans = 0;        int flag = -1;        for(int i = 1; i <= m; i++)        {            if(ans < dp[n][i])            {                flag = i;                ans = dp[n][i];            }        }        printf("%d\n", ans);        tmpx = n, tmpy = flag;        cur = 0;        if(tmpy > 0)            Printf(tmpx, tmpy);        if(t != 0)            puts("");    }    return 0;}


Greatest Common Increasing Subsequence

Time Limit: 2 Seconds      Memory Limit: 65536 KB      Special Judge

You are given two sequences of integer numbers. Write a program to determine their common increasing subsequence of maximal 
possible length.

Sequence S1, S2, ..., SN of length N is called an increasing subsequence of a sequence A1, A2, ..., AM of length M if there exist 1 <= i1 < i2 < ...< iN <= M such that Sj = Aij for all 1 <= j <= N, and Sj < Sj+1 for all 1 <= j < N. 


Input

Each sequence is described with M - its length (1 <= M <= 500) and M integer numbers Ai (-2^31 <= Ai < 2^31) - the sequence itself.


Output

On the first line of the output print L - the length of the greatest common increasing subsequence of both sequences. On the second line print the subsequence itself. If there are several possible answers, output any of them.


This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.


Sample Input

1

5
1 4 2 5 -12
4
-12 1 2 4


Sample Output

2
1 4


Source: Northeastern Europe 2003, Northern Subregion
Submit    Status