bzoj 4275 Badania naukowe —— DP

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4275

枚举 \( C \) 在 \( A \) 和 \( B \) 中的位置,然后取它前后的最长子序列;

\( n^2 \) DP即可,呵呵。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const xn=3005;
int n,m,l,a[xn],b[xn],c[xn],f[xn][xn],g[xn][xn],pa[xn],pb[xn];
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return f?ret:-ret;
}
int main()
{
  n=rd(); for(int i=1;i<=n;i++)a[i]=rd();
  m=rd(); for(int i=1;i<=m;i++)b[i]=rd();
  l=rd(); for(int i=1;i<=l;i++)c[i]=rd();
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
      {
    f[i][j]=max(f[i-1][j],f[i][j-1]);
    if(a[i]==b[j])f[i][j]=max(f[i][j],f[i-1][j-1]+1);
      }
  if(l==0){printf("%d\n",f[n][m]); return 0;}//
  for(int i=n;i;i--)
    for(int j=m;j;j--)
      {
    g[i][j]=max(g[i+1][j],g[i][j+1]);
    if(a[i]==b[j])g[i][j]=max(g[i][j],g[i+1][j+1]+1);
      }
  memset(pa,-1,sizeof pa);
  for(int i=1;i<=n;i++)
      for(int j=i,k=l;j;j--)
    {
      if(a[j]==c[k])k--;
      if(k==0){pa[i]=j; break;}
    }
  memset(pb,-1,sizeof pb);
  for(int i=1;i<=m;i++)
      for(int j=i,k=l;j;j--)
    {
      if(b[j]==c[k])k--;
      if(k==0){pb[i]=j; break;}
    }
  int ans=-1;
  for(int i=1;i<=n;i++)
    if(pa[i]!=-1)
      for(int j=1;j<=m;j++)
    if(pb[j]!=-1)ans=max(ans,f[pa[i]-1][pb[j]-1]+g[i+1][j+1]);
  if(ans==-1)puts("-1");//
  else printf("%d\n",ans+l);
  return 0;
}

 

posted @ 2018-12-06 10:47  Zinn  阅读(130)  评论(0编辑  收藏  举报