【hdu4333】扩展kmp算法

原题链接
思路比较简单。把原串扩大一倍,然后以原串为模板串,用扩展kmp算法求出每个位置的最大前缀即可。(WA了一天了,也不知道改了哪个地方就对了…………)

#include<iostream>
#include<cstdio>
#define maxl 1000100
using namespace std;
char s1[maxl*2],s2[maxl*2];
int len,pre[maxl],temp;
void getpre(char*s){
    pre[1]=pre[0]=0;
    for(int i=1;i<len;i++){
        int j=pre[i];
        while(j&&s[i]!=s[j])j=pre[j];
        pre[i+1]=s[i]==s[j]?j+1:0;      
    }
    temp=len%(len-pre[len])==0?len/(len-pre[len]):1;
    s[len]='\0';
}
void getst(){
    len=0;
    for(char c=getchar();c!='\n'&&c!=' '&&c!=EOF;c=getchar()){
        s2[len]=s1[len]=c;
        len++;
    }
    getpre(s1); 
    for(int i=len;i<2*len;i++)s2[i]=s1[i-len];  
    s2[2*len]='\0';
}
int f[maxl];
void getf(char*s,int*f){
    f[0]=len,f[1]=len-1;
    for(int i=0;i<len;i++)if(s[i]!=s[i+1]){f[1]=i;break;}
    int k=1;
    for(int i=2;i<=len;i++){
        int p=k+f[k]-1,l=f[i-k];
        if(i+l<=p)f[i]=l;else{
            int j=max(0,p-i+1);
            while(i+j<len&&s[i+j]==s[j])j++;
            f[i]=j;
            k=i;
        }
    }   
}
int ex[maxl];
void exkmp(char*T,char*P){
    getf(P,f);
    ex[0]=ex[1]=len;
    for(int i=0;i<len;i++)if(P[i]!=T[i+1]){ex[1]=i;break;}
    int k=1;
    for(int i=2;i<len;i++){
        int p=k+ex[k]-1,l=f[i-k];
        if(i+l<=p)ex[i]=l;else{
            int j=max(0,p-i+1);
            while(i+j<2*len&&T[i+j]==P[j])j++;
            ex[i]=j;k=i;
        }
    }
}
int main(){
    freopen("4333.in","r",stdin);
    freopen("wode.out","w",stdout);
    int T;
    scanf("%d",&T);
    getchar();
    for(int j=1;j<=T;j++){
        getst();
        exkmp(s2,s1);
        int c1=0,c2=0,c3=0;
        for(int i=0;i<len;i++)if(ex[i]>=len)c1++;
        else if(s2[i+ex[i]]<s1[ex[i]])c2++;
        else c3++;
        printf("Case %d: %d %d %d\n",j,c2/temp,c1/temp,c3/temp);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值