lightOJ 1416 Superb Sequence(求C的最短最小子列X使得AB是X的子列)

题目链接:http://lightoj.com/volume_showproblem.php?problem=1416

题意:给出三个串ABC。求一个C的子列X使得AB是X的子列。X最短,设这个最短串长度为L。求出这个长度为L的满足题意的有多少个?然后输出字典序最小的。

思路:分三步:(1)求出最短的串X。 f[i][j][k]表示C的前k个包含AB的前i、前j个的最短串;(2)设最短串长度为L,求长度为L的有多少个;(3)构造字典序最小的一个,这一 步可以按照贪心的思想,每次在满足长度为L时若A[i]和B[j]都可以选择最小的。这三步基本相同。DP前,预处理出next[i][j]表示从C的i 位置起字母j下一次出现的位置。

 

int f[N][N][N*3],p[N][N][N*3];
int n,m,K;
string a,b,c;
int next[N*3][26];

void init()
{
    int i,j;
    clr(next,-1);
    FORL0(i,K-1)
    {
        FOR0(j,26) next[i][j]=next[i+1][j];
        next[i][c[i]-'a']=i;
    }
}

void up(int &x,int y)
{
    x+=y;
    if(x>=mod) x-=mod;
}

int check(string a,int i,int n,int k)
{
    int x,t;
    for(x=i;x<n;x++)
    {
        t=a[x]-'a';
        if(next[k][t]==-1) return 0;
        k=next[k][t]+1;
    }
    return 1;
}

int DFS(int i,int j,int k)
{
    if(i==n)
    {
        if(check(b,j,m,k)) return m-j;
        return INF;
    }
    if(j==m)
    {
        if(check(a,i,n,k)) return n-i;
        return INF;
    }
    if(f[i][j][k]!=-1) return f[i][j][k];
    int ans=INF;
    if(a[i]==b[j])
    {
        if(next[k][a[i]-'a']>=0)
        {
            ans=min(ans,DFS(i+1,j+1,next[k][a[i]-'a']+1)+1);
        }
    }
    else
    {
        if(next[k][a[i]-'a']>=0)
        {
            ans=min(ans,DFS(i+1,j,next[k][a[i]-'a']+1)+1);
        }
        if(next[k][b[j]-'a']>=0)
        {
            ans=min(ans,DFS(i,j+1,next[k][b[j]-'a']+1)+1);
        }
    }
    return f[i][j][k]=ans;
}


int DFS1(int i,int j,int k)
{
    if(i==n||j==m) return 1;
    if(p[i][j][k]!=-1) return p[i][j][k];
    int ans=0,x;
    if(a[i]==b[j])
    {
        x=next[k][a[i]-'a'];
        if(x!=-1&&DFS(i+1,j+1,x+1)+1==f[i][j][k]) up(ans,DFS1(i+1,j+1,x+1));
    }
    else
    {
        x=next[k][a[i]-'a'];
        if(x!=-1&&DFS(i+1,j,x+1)+1==f[i][j][k]) up(ans,DFS1(i+1,j,x+1));
        x=next[k][b[j]-'a'];
        if(x!=-1&&DFS(i,j+1,x+1)+1==f[i][j][k]) up(ans,DFS1(i,j+1,x+1));
    }
    return p[i][j][k]=ans;
}


string ans;


void DFS2(int i,int j,int k)
{
    if(i==n)
    {
        ans+=b.substr(j,m-j);
        return;
    }
    if(j==m)
    {
        ans+=a.substr(i,n-i);
        return;
    }
    int L=f[i][j][k],x,y;
    if(a[i]==b[j])
    {
        ans+=a[i];
        x=next[k][a[i]-'a'];
        DFS2(i+1,j+1,x+1);
    }
    else
    {
        x=next[k][a[i]-'a'];
        y=next[k][b[j]-'a'];
        if(x!=-1&&y!=-1&&L==DFS(i+1,j,x+1)+1&&L==DFS(i,j+1,y+1)+1)
        {
            if(a[i]<b[j])
            {
                ans+=a[i];
                DFS2(i+1,j,x+1);
            }
            else
            {
                ans+=b[j];
                DFS2(i,j+1,y+1);
            }
        }
        else if(x!=-1&&L==DFS(i+1,j,x+1)+1)
        {
            ans+=a[i];
            DFS2(i+1,j,x+1);
        }
        else
        {
            ans+=b[j];
            DFS2(i,j+1,y+1);
        }
    }
}


void deal()
{
    clr(f,-1); clr(p,-1);
    int minLen=DFS(0,0,0);
    if(minLen>=INF)
    {
        puts("0");
        puts("NOT FOUND");
        return;
    }
    int cnt=DFS1(0,0,0);
    PR(cnt);
    ans="";
    DFS2(0,0,0);
    PR(ans);
}


int main()
{
    int num=0;
    rush()
    {
        RD(a); n=SZ(a);
        RD(b); m=SZ(b);
        RD(c); K=SZ(c);
        init();
        printf("Case %d: ",++num);
        deal();
    }
}

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值