CF25E:Test——题解

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\n",ans);
    return 0;
}

 

posted @ 2017-12-09 12:49  luyouqi233  阅读(379)  评论(0编辑  收藏  举报