题意:给出三个序列,求出前两个的公共子序列,且包含第三个序列,要求长度最长。
n<=3000.
我仿佛是个傻逼。。
把最长公共子序列分解一下,变成一段+第三个序列+一段。
那么求个前缀后缀然后xjb记录一下就出来了。
dp我是真的弱= =
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=4e3+5;
int n,m,q,a[N],b[N],c[N],d[N],e[N];
int g[N][N],f[N][N],ans=-1;
int main()
{
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a[i]);
scanf("%d",&m);
fo(i,1,m)scanf("%d",&b[i]);
scanf("%d",&q);
fo(i,1,q)scanf("%d",&c[i]);
fo(i,1,n)
{
fo(j,1,m)
f[i][j]=a[i]==b[j]?(f[i-1][j-1]+1):max(f[i-1][j],f[i][j-1]);
}
if (!q)
{
printf("%d\n",f[n][m]);
return 0;
}
fd(i,n,1)
fd(j,m,1)
g[i][j]=a[i]==b[j]?(g[i+1][j+1]+1):max(g[i][j+1],g[i+1][j]);
int k;
fo(i,1,n)
{
k=1;
fo(j,i,n)
{
if (a[j]==c[k])k++;
if (k>q)
{
d[i]=j;
break;
}
}
}
fo(i,1,m)
{
k=1;
fo(j,i,m)
{
if (b[j]==c[k])k++;
if (k>q)
{
e[i]=j;
break;
}
}
}
fo(i,1,n)
if (d[i])
fo(j,1,m)
if (e[j])
ans=max(ans,f[i-1][j-1]+g[d[i]+1][e[j]+1]+q);
printf("%d\n",ans);
return 0;
}