(线性dp)最长公共上升子序列

题意,最长公共上升子序列

dp数组记录以ai和bj结尾的两子串的最长公共上升子序列的长度

先讨论a[i]!=b[j]的情况,此时相当于从状态(a[i-1],b[j])增加了一个a[i]元素但a[i]!=b[j],所以应当继承状态(a[i-1],b[j]);那么为什么不去继承状态(a[i],b[j-1])呢,因为是从状态(a[i],0)==0开始的,没能继承之前的状态。

现在讨论当a[i]b[j]的情况。对于当前的a[i]和b[j](a[i]不一定等于b[j],状态(a[i],b[j])表示以a[i]和b[j]结尾的两子串的最长公共上升子序列的长度),尝试加入b[j+1],此时假定a[i]b[j+1],那么必定要发生转移,从b串中找到一个b[x],当b[x]<b[j+1]==a[i]时,就可由状态(a[i-1],b[x])+1转移到(a[i],b[j+1])。

对于b[x],b[x]a[y]<b[j+1]a[i],y<i,x<j+1

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<cmath>
#define ll long long
#define fastio {ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);}
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 1e9;

int dp[505][505];
int main()
{
    //fastio;
    int t;
    scanf("%d", &t);
    while (t--)
    {
        memset(dp, 0, sizeof(dp));
        int n, m;
        scanf("%d", &n);
        vector<int>a(n + 1);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        scanf("%d", &m);
        vector<int>b(m + 1);
        for (int i = 1; i <= m; i++)
            scanf("%d", &b[i]);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
                if (a[i] == b[j])
                {
                    for (int k = 0; k < j; k++)
                        if (b[k] < a[i])
                            dp[i][j] = max(dp[i][j], dp[i - 1][k] + 1);
                }
                else
                    dp[i][j] = dp[i - 1][j];
        }
        int ans = 0;
        for (int i = 1; i <= m; i++)
            ans = max(ans, dp[n][i]);
        printf("%d\n", ans);
        if (t)printf("\n");
    }
    return 0;

}

猜你喜欢

转载自www.cnblogs.com/ruanbaiQAQ/p/12915028.html