题意:
求两个序列的LCIS,最长公共上升子序列。
题解:
结合一下LCS和LIS即可。
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
a
[
1
⋯
i
]
a[1\cdots i]
a[1⋯i]与
b
[
1
⋯
j
]
b[1\cdots j]
b[1⋯j]构成的LCIS长度。当
a
[
i
]
=
=
b
[
j
]
a[i]==b[j]
a[i]==b[j]时,
f
[
i
]
[
j
]
=
max
0
≤
k
<
j
,
b
[
j
]
<
a
[
i
]
f
[
i
−
1
]
[
k
]
+
1
f[i][j]=\max_{0\leq k<j,b[j]<a[i]}f[i-1][k]+1
f[i][j]=0≤k<j,b[j]<a[i]maxf[i−1][k]+1
显然可以用
O
(
n
3
)
O(n^3)
O(n3)解决,但是可以优化一下。在内层循环
b
[
j
]
b[j]
b[j]时,
a
[
i
]
a[i]
a[i]是固定的,且
b
[
1
⋯
j
−
1
]
b[1\cdots j-1]
b[1⋯j−1]是固定的,每次实际上只是让
b
[
j
]
b[j]
b[j]加入决策集合。对于决策集合只增不减的情景,可以用一个变量维护决策集合当前的信息,避免重复扫描,把转移降低一个复杂度。对于每个
a
[
i
]
a[i]
a[i],先初始化
v
a
l
=
0
val=0
val=0,代表当前最长的LCIS,当
b
[
j
]
<
a
[
i
]
b[j]<a[i]
b[j]<a[i]时,
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
,
v
a
l
=
m
a
x
(
f
[
i
]
[
j
]
,
v
a
l
)
f[i][j]=f[i-1][j],val=max(f[i][j],val)
f[i][j]=f[i−1][j],val=max(f[i][j],val);当
b
[
j
]
=
=
a
[
i
]
b[j]==a[i]
b[j]==a[i]时,
f
[
i
]
[
j
]
=
v
a
l
+
1
f[i][j]=val+1
f[i][j]=val+1。由
b
[
j
]
=
=
a
[
i
]
b[j]==a[i]
b[j]==a[i]维护LCS,由
b
[
j
]
<
a
[
i
]
b[j]<a[i]
b[j]<a[i]维护LIS。
AC代码:
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <iomanip>
#include <cstdlib>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define lep(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define fir first
#define sec second
#define All(x) x.begin(),x.end()
#define ms(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define multi int T;scanf("%d",&T);while(T--)
using namespace std;
typedef long long ll;
typedef double db;
const int N=3e3+5;
const int mod=10007;
const db pi=acos(-1.0);
int a[N],b[N],n,dp[N][N];
string s;
int main()
{
#ifndef ONLINE_JUDGE
freopen("D:\\work\\data.in","r",stdin);
#endif
int n;
scanf("%d",&n);
rep(i,1,n) scanf("%d",&a[i]);
rep(i,1,n) scanf("%d",&b[i]);
rep(i,1,n){
int val=0;
rep(j,1,n){
if(a[i]==b[j]) dp[i][j]=val+1;
else{
dp[i][j]=dp[i-1][j];
if(b[j]<a[i]) val=max(val,dp[i][j]);
}
}
}
int ans=0;
rep(i,1,n) ans=max(ans,dp[n][i]);
printf("%d",ans);
}