题目链接: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();
}
}