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