zoukankan      html  css  js  c++  java
  • 【BZOJ4275】[ONTAK2015]Badania naukowe DP

    【BZOJ4275】[ONTAK2015]Badania naukowe

    Description

    给定三个数字串A,B,C,请找到一个A,B的最长公共子序列,满足C是该子序列的子串。

    Input

    第一行包含一个正整数n(1<=n<=3000),表示A串的长度。
    第二行包含n个正整数,其中第i个数表示A[i](1<=A[i]<=1000)。
    第三行包含一个正整数m(1<=m<=3000),表示B串的长度。
    第四行包含m个正整数,其中第i个数表示B[i](1<=B[i]<=1000)。
    第五行包含一个整数k(0<=k<=3000),表示C串的长度。
    第六行包含k个正整数,其中第i个数表示C[i](1<=C[i]<=1000)。

    Output

    输出一个整数,即满足条件的最长公共子序列的长度,如果无解输出-1。特别的,如果k为0且无解,请输出0。

    Sample Input

    7
    1 2 2 3 1 1 2
    6
    1 2 1 3 1 2
    2
    3 2

    Sample Output

    4

    HINT

    找到的最长个公共子序列为(1,2,3,2)。

    题解:我们先对于A和B的每个位置,处理出所有以i为结尾的,与C相同的子序列中,起始点最靠右的起始点位置pa[i]和pb[i]。然后处理出A和B的前缀最长公共子序列和后缀最长公共子序列f和g。用f[pa[i]-1][pb[j]-1]+g[i+1][j+1]更新答案即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    int A,B,C,ans;
    int a[3010],b[3010],c[3010];
    int f[3010][3010],g[3010][3010],pa[3010],pb[3010];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	int i,j,k;
    	for(A=rd(),i=1;i<=A;i++)	a[i]=rd();
    	for(B=rd(),i=1;i<=B;i++)	b[i]=rd();
    	for(C=rd(),i=1;i<=C;i++)	c[i]=rd();
    	for(i=1;i<=A;i++)	for(j=1;j<=B;j++)
    	{
    		f[i][j]=max(f[i][j-1],f[i-1][j]);
    		if(a[i]==b[j])	f[i][j]=max(f[i][j],f[i-1][j-1]+1);
    	}
    	if(!C)
    	{
    		printf("%d",f[A][B]);
    		return 0;
    	}
    	for(i=A;i>=1;i--)	for(j=B;j>=1;j--)
    	{
    		g[i][j]=max(g[i][j+1],g[i+1][j]);
    		if(a[i]==b[j])	g[i][j]=max(g[i][j],g[i+1][j+1]+1);
    	}
    	for(i=1;i<=A;i++)
    	{
    		for(k=i,j=C;k>=1;k--)
    		{
    			if(a[k]==c[j])	j--;
    			if(!j)	break;
    		}
    		pa[i]=k-1;
    	}
    	for(i=1;i<=B;i++)
    	{
    		for(k=i,j=C;k>=1;k--)
    		{
    			if(b[k]==c[j])	j--;
    			if(!j)	break;
    		}
    		pb[i]=k-1;
    	}
    	for(i=1;i<=A;i++)	for(j=1;j<=B;j++)	if(pa[i]!=-1&&pb[j]!=-1)	ans=max(ans,f[pa[i]][pb[j]]+g[i+1][j+1]+C);
    	if(!ans)	printf("-1");
    	else	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    013.[转] 云原生
    012.[转] 云计算
    011.maven 继承与聚合
    Window常用且通用快捷键
    Hibernate Validator Engine的用法
    Mybatis书写
    Ajax错误
    apache commons lang架包介绍
    Mybatis使用Mybatis-generator插件及配置(数据库逆向工程)
    二分搜索树
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7749406.html
Copyright © 2011-2022 走看看