【题解】CH5101 LCIS 线性DP

题目链接

描述

熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。
小沐沐说,对于两个数列A和B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。
奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。不过,只要告诉奶牛它的长度就可以了。数列A和B的长度均不超过3000。

输入格式

第一行N,表示A,B的长度。
第二行,串A。
第三行,串B。

输出格式

输出长度。

样例输入

4
2 2 1 3
2 1 2 3

样例输出

2

数据范围与约定

1<=N<=3000,A,B中的数字不超过2^31-1


我们用 F [ i , j ] F[i,j] F[i,j] 表示 A 1 , ⋯ &ThinSpace; , A i A_1,\cdots ,A_i A1,,Ai B 1 , ⋯ &ThinSpace; , B j B_1,\cdots,B_j B1,,Bj 可以构成的以 B j B_j Bj 为结尾的LCIS的长度:
F [ i , j ] = { F [ i − 1 , j ] , A i ≠ B j max ⁡ 0 ≤ k &lt; j , B k &lt; B j { F [ i − 1 , k ] } + 1 = max ⁡ 0 ≤ k &lt; j , B k &lt; A i { F [ i − 1 , k ] } + 1 , A i = B j F[i,j]=\begin{cases}F[i-1,j],\quad A_i\neq B_j\\\max\limits_{0\leq k&lt;j,B_k&lt;B_j}\{F[i-1,k]\}+1=\max\limits_{0\leq k&lt;j,B_k&lt;A_i}\{F[i-1,k]\}+1,\quad A_i=B_j\end{cases} F[i,j]=F[i1,j],Ai̸=Bj0k<j,Bk<Bjmax{F[i1,k]}+1=0k<j,Bk<Aimax{F[i1,k]}+1,Ai=Bj
在转移过程中,我们把满足 0 ≤ k &lt; j , B k &lt; A i 0\le k&lt;j,B_k&lt;A_i 0k<j,Bk<Ai k k k 构成的集合称为 F [ i , j ] F[i,j] F[i,j] 进行状态转移时的决策集合,记为 S ( i , j ) S(i,j) S(i,j) 。注意到,在第二层循环 j j j 1 1 1 增加到 n n n 时, B k &lt; A i B_k&lt;A_i Bk<Ai是固定的。因此当变量 j j j 增加 1 1 1 时, k k k 的取值范围从 0 ≤ k &lt; j 0\le k&lt;j 0k<j 变为 0 ≤ k &lt; j + 1 0\le k&lt;j+1 0k<j+1,即整数 j j j 可能会进入新的决策集合。也就是说,我们只需要 O ( 1 ) O(1) O(1) 地检查条件 B j &lt; A i B_j&lt;A_i Bj<Ai 是否满足,已经在决策集合中的数则一定不会被去除:
S ( i , j + 1 ) = { S ( i , j ) B j ≥ A i S ( i , j ) ∪ { j } B j &lt; A i S(i,j+1)=\begin{cases}S(i,j)\quad B_j\geq A_i\\S(i,j)\cup \{j\}\quad B_j&lt;A_i\end{cases} S(i,j+1)={S(i,j)BjAiS(i,j){j}Bj<Ai
最终目标是 max ⁡ 1 ≤ j ≤ m F [ n , j ] \max\limits_{1\leq j\leq m}F[n,j] 1jmmaxF[n,j]
摘自李煜东《算法竞赛进阶指南》。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=3e3+10;
int f[N][N],a[N],b[N],n,ans;
int main()
{
	//freopen("in.txt","r",stdin);
    scanf("%d",&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 val=0;//决策集合S(i,j)中f[i-1][k]的最大值
		if(b[0]<a[i])val=f[i-1][0];//j=1时,0可以作为k的取值
		for(int j=1;j<=n;j++)
		{
			if(a[i]==b[j])f[i][j]=val+1;
			else f[i][j]=f[i-1][j];
			if(b[j]<a[i])val=max(val,f[i-1][j]);
			//j即将增大为j+1,检查j能否进入新的决策集合 
		}
	}
	for(int i=1;i<=n;i++)ans=max(ans,f[n][i]);
	printf("%d\n",ans);
	return 0;
}

总结

最长公共上升子序列,很经典。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值