HDU 4681 String 解题报告

2013 暑假多校训练 8 总结

题目

题意:

有三个字符串ABC,现在要求一个最长的字符串D,使得:

1、D是A的子序列。

2、D是B的子序列。

3、C是D的子串。

输出D的长度。


题解:

首先对于A,求以J为结尾时,最大的I,使得C是A[i]~A[j]的子序列。B同理。

然后枚举A、B各自包含C的区间,那么两个区间外的位置用LCS计算能在C两端加的字符数。


有点卡常数,T了两次,还是自己写得不够好吧。


//Time:593ms
//Memory:10520KB
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define MAXN 1010
#define INF 1000000007

int lcdp[2][MAXN][MAXN];
int dp[MAXN][MAXN];
int mbegin[2][MAXN];
char sta[MAXN],stb[MAXN],stc[MAXN];
void rever(char s[],int len)
{
    for(int i=0,j=len-1;i<j;++i,--j)
        swap(s[i],s[j]);
}
void cal(char s1[],char s2[],int arr[],int len1,int len2)
{
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<len1;++i)
        for(int j=0;j<len2;++j)
        {
            dp[i][j]=max(dp[i][j],i>0?dp[i-1][j]:-1);
            if(s1[i]==s2[j])
            {
                if(j==0)    dp[i][j]=i;
                dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]);
            }
        }
    for(int i=0;i<=len1;++i)
        arr[i]=dp[i][len2];
}
void cal2(char s1[],char s2[],int arr[][MAXN],int len1,int len2)
{
    for(int i=0;i<len1;++i)
        for(int j=0;j<len2;++j) arr[i][j]=0;

    for(int i=0;i<len1;++i)
        arr[i][0]=max((int)(s1[i]==s2[0]),i?arr[i-1][0]:0);
    for(int i=1;i<len2;++i)
        arr[0][i]=max((int)(s1[0]==s2[i]),arr[0][i-1]);
    for(int i=1;i<len1;++i)
        for(int j=1;j<len2;++j)
        {
            arr[i][j]=max(arr[i-1][j],arr[i][j-1]);
            if(s1[i]==s2[j])    arr[i][j]=max(arr[i][j],arr[i-1][j-1]+1);
        }
}
int main()
{
    //freopen("/home/moor/Code/1006.txt","r",stdin);
    int ncase,la,lb,lc,ans;
    scanf("%d",&ncase);
    for(int h=1;h<=ncase;++h)
    {
        scanf("%s%s%s",sta,stb,stc);
        la=strlen(sta);lb=strlen(stb);lc=strlen(stc);
        ans=0;
        cal(sta,stc,mbegin[0],la,lc);
        cal(stb,stc,mbegin[1],lb,lc);
        cal2(sta,stb,lcdp[0],la-lc+1,lb-lc+1);
        rever(sta,la);
        rever(stb,lb);
        cal2(sta,stb,lcdp[1],la-lc+1,lb-lc+1);
        for(int i=1;i<=la;++i)
            if(mbegin[0][i]>=0)
                for(int j=1;j<=lb;++j)
                    if(mbegin[1][j]>=0)
                    {
                        int t1=mbegin[0][i],t2=mbegin[1][j];
                        ans=max(ans,((t1>0&&t2>0)?lcdp[0][t1-1][t2-1]:0)+
                            ((i<la&&j<lb)?lcdp[1][la-i-1][lb-j-1]:0));
                    }
        printf("Case #%d: %d\n",h,ans+lc);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值