bzoj3304[Shoi2005]带限制的最长公共子序列 DP
题意:给出三个序列,求出前两个的公共子序列,且包含第三个序列,要求长度最长。
这道题目怎么做呢,f[i][j]表示a串1-i,b串1-j的最长,g[i][j]表示a串i-n,b串j-m最长,
那么只需要判断中间有没有包好c串就OK了,这样都是O(n^2)的。
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<set> #include<map> #include<iostream> #include<algorithm> #define pa pair<int,int> #define ll long long #define N 3008 #define mx 1e9 using namespace std; int sc() { int i=0,f=1; char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar(); return i*f; } int fa[N],fb[N]; int f[N][N],g[N][N]; int a[N],b[N],c[N]; int La,Lb,Lc,ans; int main() { La=sc();for(int i=1;i<=La;i++)a[i]=sc(); Lb=sc();for(int i=1;i<=Lb;i++)b[i]=sc(); Lc=sc();for(int i=1;i<=Lc;i++)c[i]=sc(); for(int i=1;i<=La;i++) for(int j=1;j<=Lb;j++) if(a[i]==b[j]) f[i][j]=f[i-1][j-1]+1; else f[i][j]=max(f[i][j-1],f[i-1][j]); if(!Lc) { printf("%d\n",f[La][Lb]); return 0; } for(int i=La;i>=1;i--) for(int j=Lb;j>=1;j--) if(a[i]==b[j]) g[i][j]=g[i+1][j+1]+1; else g[i][j]=max(g[i][j+1],g[i+1][j]); for(int i=1;i<=La;i++) if(i>1&&a[i-1]!=c[1])fa[i]=fa[i-1]; else for(int j=1,k=i;k<=La;k++) { if(a[k]==c[j])j++; if(j>Lc){fa[i]=k;break;} } for(int i=1;i<=Lb;i++) if(i>1&&b[i-1]!=c[1])fb[i]=fb[i-1]; else for(int j=1,k=i;k<=Lb;k++) { if(b[k]==c[j])j++; if(j>Lc){fb[i]=k;break;} } for(int i=1;i<=La;i++) if(fa[i]) for(int j=1;j<=Lb;j++) if(fb[j]) ans=max(ans,f[i-1][j-1]+g[fa[i]+1][fb[j]+1]); ans?cout<<ans+Lc:cout<<-1; }