最长公共上升子序列 (poj 2127) (Greatest Common Increasing Subsequence)

\(Greatest Common Increasing Subsequence\)

大致题意:给出两个长度不一定相等的数列,求其中最长的公共的且单调递增的子序列(需要具体方案)



\(solution:\)

这道题如果不看具体方案,且我们要求的子序列不存在相同的元素,那么我们可以用 \(cdq\) 分治来搞搞,首先我们记录第二个数列中的元素在第一个数列里出现的位置(假设不存在重复,没有的不管),然后我们的第二个数列的每一个元素就有两个权值了,这是我们只需要两个权值均单调递增即可(这是 $cdq $ 完全可以干的事情)

但是这道题的限制太多了,不过相应的它的数据范围也比较宽松允许 \(n^2\) ,而众所周知复杂度越高的算法覆盖面越广,而且我们知道我们要求的序列其中每一个元素必然在两个数列中都存在且从前往后排列,所以我们模仿LCS的几种求法中的第一种。其实这一题和它很像,只不过由于“上升”这两个字而是它状态转移发生了变化。

我们由于要“上升”,那我们的转移显然不能只看上一个状态,在枚举到了哪一个 \(A[i]\) 时,我们所有的小于 $A[i] $ 的 \(B[j]\) 都可以作为待定的“上一个状态”,只要枚举到了一个和 $A[i] $ 相同的 \(B[j]\) 我们都可以用这个“上一个状态”转移过来也就是:

\(F[i][j]=max\{F[i-1][k]_{B[k]<A[i]} \}+1\)



\(code:\)

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int

using namespace std;

int t,n,m,ans,tt;
int a[505];
int b[505];
int f[505][505];
int s[505][505];

inline int qr(){
    register char ch; register bool sign=0; rg res=0;
    while(!isdigit(ch=getchar())) if(ch=='-')sign=1;
    while(isdigit(ch)) res=res*10+(ch^48),ch=getchar();
    return sign?-res:res;
}

inline void print(int i,int j){
    if(i)for(;i;--i)if(s[i][j]!=-1)
        print(i-1,s[i][j]),printf("%d ",b[j]);
}

int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    t=qr();
    while(t--){
        n=qr(); for(rg i=1;i<=n;++i) a[i]=qr();
        m=qr(); for(rg i=1;i<=m;++i) b[i]=qr();
        for(rg i=1;i<=n;++i){ rg v=0;
            for(rg j=1;j<=m;++j){ s[i][j]=-1;
                if(a[i]==b[j])f[i][j]=f[i-1][v]+1,s[i][j]=v;
                else f[i][j]=f[i-1][j];
                if(b[j]<a[i]&&f[i-1][j]>f[i-1][v])v=j;
            }
        } ans=0;
        for(rg i=1;i<=m;++i) if(f[n][i]>f[n][ans])ans=i;
        printf("%d\n",f[n][ans]);
        if(f[n][ans]){print(n,ans); puts("");}
    }
    return 0;
}

转载于:https://www.cnblogs.com/812-xiao-wen/p/10998305.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值