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();

    }

}

 

 

 

你可能感兴趣的:(sequence)