最长公共上升子序列(LCIS)
dp[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合
两个子集:
1.不包含a[i]的子集,最大值是dp[i - 1][j];
2.包含a[i]的子集
O(nmm)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int T,n,m,a[505],b[505],dp[505][505];
int main()
{
cin >> T;
while(T--)
{
cin >> n;
for(int i=1;i<=n;i++)
cin >> a[i];
cin >> m;
for(int i=1;i<=m;i++)
cin >> b[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
dp[i][j]=dp[i-1][j];//不包含a[i]
if(a[i]==b[j])//包含a[i]
{
int ma=1;
for(int k=1;k<j;k++)
{
if(a[i]>b[k])//a[i]==b[j]
{
ma=max(ma,dp[i-1][k]+1);
}
}
dp[i][j]=max(dp[i][j],ma);
}
}
}
int res=0;
for(int i=1;i<=m;i++)
res=max(res,dp[n][i]);
cout << res << endl;
if(T)
cout << endl;
}
return 0;
}
每次循环求得的ma是满足a[i] > b[k]的f[i - 1][k] + 1的前缀最大值。
因此可以直接将maxv提到第一层循环外面,减少重复计算
O(n*m)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int T,n,m,a[505],b[505],dp[505][505];
int main()
{
cin >> T;
while(T--)
{
cin >> n;
for(int i=1;i<=n;i++)
cin >> a[i];
cin >> m;
for(int i=1;i<=m;i++)
cin >> b[i];
for(int i=1;i<=n;i++)
{
int ma=1;
for(int j=1;j<=m;j++)
{
dp[i][j]=dp[i-1][j];//不包含a[i]
//包含a[i]==b[j]
if(a[i]>b[j])//更新ma
ma=max(ma,dp[i-1][j]+1);
if(a[i]==b[j])
dp[i][j]=max(dp[i][j],ma);//取包含或不包含a[i]的最大值
}
}
int res=0;
for(int i=1;i<=m;i++)
res=max(res,dp[n][i]);
cout << res << endl;
if(T)
cout << endl;
}
return 0;
}
改进版
```cpp
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int T,n,m,a[505],b[505],dp[505][505];
int main()
{
cin >> T;
while(T--)
{
cin >> n;
for(int i=1;i<=n;i++)
cin >> a[i];
cin >> m;
for(int i=1;i<=m;i++)
cin >> b[i];
for(int i=1;i<=n;i++)
{
int ma=0;
for(int j=1;j<=m;j++)
{
dp[i][j]=dp[i-1][j];//不包含a[i]
//包含a[i]
if(a[i]==b[j])
dp[i][j]=ma+1;
if(a[i]>b[j]&&ma<dp[i-1][j])//更新ma
ma=dp[i-1][j];
}
}
int res=0;
for(int i=1;i<=m;i++)
res=max(res,dp[n][i]);
cout << res << endl;
if(T)
cout << endl;
}
return 0;
}
空间降为O(m)
f[i][j]都是由f[i-1][j]得来的,因此可以优化空间得dp[j]
```cpp
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
int T,n,m,a[505],b[505],dp[505];
int main()
{
cin >> T;
while(T--)
{
memset(dp,0,sizeof(dp));
cin >> n;
for(int i=1;i<=n;i++)
cin >> a[i];
cin >> m;
for(int i=1;i<=m;i++)
cin >> b[i];
for(int i=1;i<=n;i++)
{
int ma=0;
for(int j=1;j<=m;j++)
{
if(a[i]==b[j])
dp[j]=ma+1;
if(a[i]>b[j]&&ma<dp[j])//更新ma
ma=dp[j];
}
}
int res=0;
for(int i=1;i<=m;i++)
res=max(res,dp[i]);
cout << res << endl;
if(T)
cout << endl;
}
return 0;
}