HDU 3336 Count The String

K - Count the string 

                                HDU - 3336

题意:例如abab这样的字符串的子字符串看为有a,ab,aba,abab四种,就是从第一个开始,每次加一个元素,也就是所有的非空前缀,其中a,ab在原字符串中出现两次,aba,abab各出现一次,所以一共六次,结果要%10007 

对,每次都是从0开始更新,很慢

分析一下这个ac代码,每次都重新定义一个新的子字符串太浪费时间了,那就要学会利用next数组来减少麻烦,其实这道题从一开始就想的复杂了,为什么每次都要找一个新的字符串呢?没必要的

next数组存放的是字符串的前缀和后缀能匹配的字符个数的最大值

        如果next[i]  == 0或-1则表示 由s的前i个字符组成的字符串的所有后缀肯定和其前缀不匹配。

        否则      由s的前i个字符组成的字符串存在某个前缀和后缀匹配的情况,也就是该前缀的出现的次数应该加上1。

例如   0 1 2 3 4 5 6 7 8

         a b a b a b a b 

        -1 0 0 1 2 3 4 5 6

这样一个例子,先判断ne[len] = 6   !=  0或-1,接着判断ne[ne[len]]即ne[6],仍然符合不等于1或是0,直到判断到结束条件时,如果ne[]某个数值等于-1或0时,结束判断

#include<iostream>  
#include<cstring>  
#include<cstdio>  
#include<algorithm>  
#include<vector>  
#include<set>  
#include<map>  
#include<queue>  
#include<cmath>  
using namespace std;  
#define maxn 200005  
int len;  
char a[maxn];  
int ne[maxn];   
void findnext()  
{  
    int i = 0, j = -1;  
    ne[0] = -1;  
    while(i < len)  
    {  
        if(j == -1 || a[i] == a[j])  
            ne[++i] = ++j;  
        else j = ne[j];  
    }  
}  
int main()  
{  
    int t;  
    scanf("%d",&t);  
    while(t--)  
    {  
        scanf("%d",&len);  
        scanf("%s",a);  
        long long ans = len;//每个前缀至少会出现一次,所以初始化答案设为所有前缀的个数即字符串长度  
        findnext();  
        for(int i = len; i > 0; i --)//倒叙遍历每一个点  
        {  
            while(ne[i] != 0 && ne[i] != -1)  
            {  
                ans ++;//符合条件时就加上该种情况  
                ne[i] = ne[ne[i]];//跳到下一个位置  
            }  
            if(ans >= 10007) ans %= 10007;  
        }  
        printf("%lld\n",ans);  
    }  
    return 0;  
}
 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值