https://vjudge.net/problem/CodeForces-25E
题目大意:给三个字符串,求最小串,使得前三个串都是它的子串。
————————————————
这题虽然是看哈希的时候做的,但上网一查啊全是KMP。
所以果断用KMP做啦!
(话说网上的题解长得都一模一样一个字都没改所以就不贴了)
对于三个串共六种排法,排列组合一下然后在把他们重合的部分减去就会是答案。
而发现对于两个字符串ab去重,我们有两种情况:
1.a的尾部是b的头部:
通过KMP解决,输出KMP后(即a被匹配完了)b被匹配到哪里了,即是ab重合长度。
2.b是a的子串:
上述KMP还有一个目的就是为了判断是否为子串,如果是的话,跳过b,a和下一个字符串相接。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int INF=2147483647; int nxt[4][100001]={0}; bool ok[4]; void getnext(int m,char s2[],int t){ int j=0; for(int i=2;i<=m;i++){ while(j!=0&&s2[j+1]!=s2[i])j=nxt[t][j]; if(s2[j+1]==s2[i])j++; nxt[t][i]=j; } return; } int KMP(int n,int m,char s1[],char s2[],int t){ int j=0,cnt=0; for(int i=1;i<=n;i++){ while(j!=0&&s2[j+1]!=s1[i])j=nxt[t][j]; if(s2[j+1]==s1[i])j++; if(j==m){ return -1; j=nxt[t][j]; } } return j; } char s[4][100001]; int len[4]; int K[4][4]; int main(){ scanf("%s%s%s",s[1]+1,s[2]+1,s[3]+1); len[1]=strlen(s[1]+1); len[2]=strlen(s[2]+1); len[3]=strlen(s[3]+1); for(int i=1;i<=3;i++){ getnext(len[i],s[i],i); for(int j=1;j<=3;j++){ if(i==j)continue; K[j][i]=KMP(len[j],len[i],s[j],s[i],i); } } int ans=INF; for(int i=1;i<=3;i++){ for(int j=1;j<=3;j++){ for(int k=1;k<=3;k++){ if(i==j||j==k||i==k)continue; int sum=len[i]+len[j]+len[k]-K[i][j]-K[j][k]; if(K[i][j]>=0&&K[j][k]>=0)ans=min(ans,sum); else{ if(K[i][j]<0&&K[i][k]<0)ans=min(ans,len[i]); else if(K[i][j]<0)ans=min(ans,sum+K[i][j]+K[j][k]-len[j]-K[i][k]); if(K[j][k]<0)ans=min(ans,sum+K[j][k]-len[k]); } } } } printf("%d ",ans); return 0; }