您的位置:首页 > 其它

hdu 3336 Count the string (kmp扩展)

2015-02-12 15:31 190 查看
题意:

给出一个字符串,求这个字符串所有前缀在字符中出现的个数。

题解:

很明显不能用暴力,kmp的扩展问题,分析这种问题最好是先写出next的代码,然后运行观察next数组对应值和字符串之间的关系,找出变化规律。

next[i]的意义表示以i-1结尾的子串中,既是真后缀又是最长前缀的长度。打印了abab这个例子的next数组变化值如下:

——————————————

i | 0 | 1 | 2 | 3 | 4 |

——————————————

s[i] | a | b | a | b |\0 |

——————————————

next[i]| -1| 0 | 0 | 1 | 2 |

——————————————

发现上面表格的规律,例如i=4时,对应0-3对应的最长公共前后缀串长度2,这个值刚好是等于a出现一次,ab出现一次的和,也就是前缀在字符串出现的次数(不包含前缀本身),但是会发现0-4的next中会重复计算,但有一点是肯定的只要
next[i]+1!=next[i+1]这样不满足递推条件,那么只单单计算以i为结尾的next[i]就可以了,那么个计算的出现次数是不包含前缀本身的,所以最后还要加上前缀的数量。

所以综上所述 ans={所有满足next[i]+1!=next[i+1]的next[i]的值}+len

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
//typedef long long lld;
const int oo=0x3f3f3f3f;
//const lld OO=1LL<<61;
const int MOD=10007;
const int maxn=200005;
char str[maxn];
int next[maxn];

void get_next(int len)
{
    int i=0;next[i]=-1;
    int j=-1;
    while(i<len)
    {
        if(j==-1||str[i]==str[j])
        {
            i++;j++;
            next[i]=j;
        }
        else
            j=next[j];
    }
}

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%s",&n,str);
        get_next(n);
        int ans=0;
        next[n+1]=0;
        for(int i=1;i<=n;i++)
            if(next[i]+1!=next[i+1])
            ans=(ans+next[i]+MOD)%MOD;
        ans=(ans+n+MOD)%MOD;
        printf("%d\n",ans);
    }
    return 0;
}
/**
abcd
-> abcdabc
abcda
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: