扩展KMP+KMP+hdu4333

来源:互联网 发布:电信 网络重构 编辑:程序博客网 时间:2024/05/01 03:08

自己就是想不到,智商是硬伤啊

思路:扩展KMP能求出一个串所有后缀串(即s[i...len])和模式串的最长公共前缀。于是只要将这个串复制一遍,拼接到后面,求出拼接后的串每个后缀与原来串的最长公共前缀即可,当公共前缀>=len时,显然相等,否则只要比较下一位就能确定这个串与原串的大小关系。至于重复串的问题,只有当这个串有循环节的时候才会产生重复串,用KMP的next数组求出最小循环节,用长度除以最小循环节得到循环节个数,在将3个答案都除以循环节个数即可。

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<cmath>#include<string>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=200010;int next[maxn/2],extend[maxn];char s[maxn],s1[maxn/2];int n;void getnext(char *ss){    n=strlen(ss);    next[0]=n;    int j=0;    while(j+1<n&&ss[j+1]==ss[j])j++;    next[1]=j;    int k=1;    for(int i=2;i<n;i++)    {        int p=next[k]+k-1;        int l=next[i-k];        if(i+l<p+1)next[i]=l;        else        {            int j=max(0,p-i+1);            while(i+j<n&&ss[i+j]==ss[j])j++;            next[i]=j;            k=i;        }    }}void getextend(char * S,char * T){    memset(next,0,sizeof(next));    getnext(T);    int j=0;    int slen=strlen(S),tlen=strlen(T);    int minlen=min(slen,tlen);    while(j<minlen&&S[j]==T[j])j++;    extend[0]=j;    int k=0;    for(int i=1;i<slen;i++)    {        int p=extend[k]+k-1;        int l=next[i-k];        if(i+l<p+1)extend[i]=l;        else        {            int j=max(0,p-i+1);            while(i+j<slen&&j<tlen&&S[i+j]==T[j])j++;            extend[i]=j;            k=i;        }    }}void getf(char * ss){    int i=0,j=-1;    int len=strlen(ss);    next[0]=-1;    while(i<len)    {        if(j==-1||ss[i]==ss[j])        {            i++,j++;            next[i]=j;        }        else j=next[j];    }}void solve(){    int L=0,E=0,G=0;    for(int i=0;i<n;i++)    {        if(extend[i]>=n)E++;        else if(s[(extend[i])%n]>=s[(i+extend[i])%n])L++;        else G++;    }    int cir=1;    int len=strlen(s1);    if(len%(len-next[len])==0)cir=len/(len-next[len]);    printf("%d %d %d\n",L/cir,E/cir,G/cir);}int main(){    int T,cas=1;    scanf("%d",&T);    while(T--)    {        scanf("%s",s);        strcpy(s1,s);        strcat(s,s1);        getextend(s,s1);        getf(s1);        printf("Case %d: ",cas++);        solve();    }    return 0;}



0 0