bzoj4275[ONTAK2015]Badania naukowe DP

168 篇文章 0 订阅

题意:给出三个序列,求出前两个的公共子序列,且包含第三个序列,要求长度最长。
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;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值