HDU 3336 一个next数组就解决了

这道题本来是用来练习KMP的  

结果貌似一个next数组就可以解决 

首先 对于每一个元字符串的前缀数组来说   至少会有一个与他匹配的 (其实就是他本身)


那么 再看看next数组的含义  每一个不为0的next数就代表着有一个子串重复过一次 比如abab   的next数组为0001 

b所在的1  就代表着长度为1 的原字符串的前缀数组重复过一个   即a重复了一次   这时  我们会发现    ab也重复过一次  那么这一次与去哪了呢?   这时  我们需要在abab的后面加一个不相干的字符 ‘ * ’,  这样 abab*  的next数组就变成了

00012   这样ab的重复的次数就出现了   在我们之后的统计的过程中 我们可以让所有在next数组中大于0的数使sum++;

然后再让sum+strlen(字符串)   就可以得出总的重复数了  别忘了模上10007

下面是AC 代码

# include <stdio.h>
# include <string.h>
char s[200000+10];
//char p[200000+10];
int sum;
int f[200000+10];
void next(int x){
    f[0]=f[1]=0;
    for(int i=1;i<x-1;i++){
        int j = f[i];
        while(j&&s[i]!=s[j]) j=f[j];
        f[i+1] = s[i]==s[j]?j+1:0;
    }
}
void solve(int x){
    for(int i=0;i<x;i++){;
        if(f[i]>0)
            sum+=1;
        //printf("%d    \n",f[i]);
    }
}
int main(){
    int T;
    while(scanf("%d",&T)!=EOF){
        int len;
        memset(f,0,sizeof(f));
        scanf("%d",&len);
        scanf("%s",s);
        sum=0;
        s[len]='*';
        s[len+1]='\0';
        next(len+1);
        solve(len+1);
        printf("%d\n",(sum+len)%10007);
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值