这个题需要把LIS和LCS合二为一
首先设f(i,j)表示从A1~Ai 和 B1~Bj 两段区间中,以Bj结尾的LCIS最大长度
注意,这里相当于固定住了“Bj是什么”这个问题,并且状态和转移是对于每一个固定的Bj才有意义的
再具体一点,因为关于A1~Ai的循环是套在B1~Bj外面的,所以在进行B1~Bj的循环时,可以将Ai看作一个常量,这个时候对答案有影响的参数就只有i,j和Bj,状态就可以设计出来。
转移:
当 A[i] !=B[j]时
f(i,j)=f(i−1,j)
当A[i]==B[j]时
f(i,j)=max{f(i−1,k)}+1 0≤k<j且Bk<Bj
然而会T。。。
所以这个时候可以转化一下DP方程
可以发现第二种情况时,A[i]==B[j]
所以方程可以写为
f(i,j)=max{f(i−1,k)}+1 0≤k<j且Bk<Ai
通过上文,我们知道在ij二重循环时,j的循环节内,可以将i看作常数
因此Bk一直都在和一个常数作比较,那么我们就可以开一个变量记下最大且满足条件的f(i−1,k),从而省去了一重循环,但是要记得每次新的i循环开始时要初始化maxf
#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
const int INF = 1 << 30;
const int MAXN = 3010;
int n;
int a[MAXN], b[MAXN],ans;
int f[MAXN][MAXN],maxf;
int main() {
cin >> n;
for(int i=1; i<=n; i++)
cin >> a[i];
for(int i=1; i<=n; i++)
cin >> b[i];
b[0] = -INF;
for(int i=1; i<=n; i++) {
maxf = 0;
for(int j=1; j<=n; j++) {
if(b[j-1] < a[i])
maxf = max(maxf,f[i-1][j-1]);
if(a[i]==b[j])
f[i][j] = max(f[i][j], maxf + 1);
else
f[i][j] = f[i-1][j];
}
}
for(int i=1; i<=n; i++)
ans = max(ans,f[n][i]);
cout << ans << endl;
return 0;
}

本文介绍了解决最长公共递增子序列(LCIS)问题的一种动态规划方法。通过对传统的LIS和LCS算法的结合改进,设计了状态转移方程并优化了计算过程,实现了高效求解。
129

被折叠的 条评论
为什么被折叠?



