【KMP】ZOJ 3587

来源:互联网 发布:数据库物理模型主键 编辑:程序博客网 时间:2024/05/01 04:38

利用了kmp的性质,kmp可以找出前i个在主串出现的次数(可覆盖),同样也可以找出后j个在主串出现的次数,只需要反向kmp就行了==,具体实现是两次预处理正向&反向,然后记录num1和num2数组

所以复杂度是线性时间.....理解kmp是重点!

#define N 100005char s[N],t[N];int next1[N],next2[N];int num1[N],num2[N];//记录i左边在主串出现次数和i右边的int l1,l2;void gao1(){    int i,j=-1;    next1[0] = -1;    for(i=1;i<l2;i++){        while(j>=0 && t[i]!=t[j+1]){            j = next1[j];        }        if(t[i]==t[j+1])j++;        next1[i] = j;    }}void gao2(){    int i,j = l2;    next2[l2-1] = l2;    for(i=l2-2;i>=0;i--){        while(j<l2 && t[i]!=t[j-1]){            j = next2[j];        }        if(t[i]==t[j-1])j--;        next2[i] = j;    }}void gaogao(){    int i,j = -1;    for(i=0;i<l1;){        if(s[i]==t[j+1]){            num1[j+1]++;            i++,j++;        } else {            if(j!=-1){                j = next1[j];            } else i++;        }    }    for(i=l2-1;i>=0;i--){        if(num1[i]){            if(next1[i]!=-1){                num1[next1[i]]+=num1[i];            }        }    }    ///////////////////////////////////////////////////////    j = l2;    for(i=l1-1;i>=0;){        if(s[i]==t[j-1]){            num2[j-1]++;            i--,j--;        } else {            if(j!=l2){                j = next2[j];            } else i--;        }    }    for(i=0;i<l2;i++){        if(num2[i]){            if(next2[i]!=l2){                num2[next2[i]] += num2[i];            }        }    }}int main(){    int ca;    scanf("%d",&ca);    while(ca--){        scanf("%s%s",s,t);        int i,j;        l1 = strlen(s);        l2 = strlen(t);        memset(num1,0,sizeof(num1));        memset(num2,0,sizeof(num2));        gao1();        gao2();        gaogao();        LL ans = 0;        for(i=0;i+1<l2;i++){            ans += (LL)num1[i]*(LL)num2[i+1];        }        printf("%lld\n",ans);    }    return 0;}



















原创粉丝点击