Hdu 3336 Count the string[KMP next数组的理解]

来源:互联网 发布:设计师必知的100 编辑:程序博客网 时间:2024/06/05 04:28
题意:求字串中【前缀+跟前缀相同的子串】的个数?

Sample Input
1
4
abab

Sample Output
6

abab:包括2个a,2个ab,1个aba,1个abab


这里要用到next值的意义:
next[i]表示前i个字符所组成的字符串最大前后缀匹配长度
举个例子:

next[5]=2, 表示下标5前面那个字符串abcab的前后缀匹配的最大长度是2,显然就是ab了

回到本题:
所求=字串的前缀个数+与前缀相同的子串
问题可以部分转化为:每个前缀的最大前后缀匹配问题

继续用上面的例子:

第一步:

对于这段子串,next[5]=2,然后后面不符合next值的递增规律了。
所以对于abcab,长度为2的后缀,即ab与前缀匹配
所以+1个ab,注意还要+1个a,既然后缀ab跟前缀ab匹配,则必有a跟前缀匹配。
也就是+2个了,其实实际上+next[5]就可以了,因为这是最长前后缀匹配长度

第二步:

对于这段子串:
next[6]=1,然后后面不符合next值的递增规律了。
所以对于abcaba,长度为1的后缀,即a与前缀匹配。
所以+1个a,也就是+next[6]了。

第三步:

对于整个串:
next[12]=4后面没有了
所以对于整个串:abcabacbabca,长度为4的后缀跟前缀匹配
所以+1个abca,+1个abc,+1个ab,+1个a,总共+4个,也就是+next[12]了

最后:
好了,刚刚一共+了7个与前缀匹配的子串
上面说了题目是求:字串的前缀个数+与前缀相同的子串个数
与前缀相同的子串个数就是7个了
然后字串的前缀个数当然就是整个串的长度了,那么就是12个

加起来就是答案:19。

到这里,有些同学就要问了,为什么next[4]为什么就不做处理了呢??

我一开始也是这么想的,为什么呢??

因为,next[4]的后面的next[5]==(正好)next[4]+1。这不是偶然,因为abca的最大后缀为1(a),而abcab的最大后缀为2(ab),这里的ab包含了前面的a。所以,如果正好next[i]+1=next[i]的话,前面的被后面包含了。

代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int N=200003;char Str[N];int n,next[N];void Get_Next(){    next[0]=-1;    int j=-1,i=0;    while(i<n){        if(j==-1||Str[i]==Str[j]){            j++;i++;            next[i]=j;        }        else j=next[j];    }}int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        scanf("%s",Str);        Get_Next();        int ans=n+next[n];        for(int i=0;i<n;i++){            if(next[i]>0&&next[i]+1!=next[i+1])            ans=(ans+next[i])%10007;        }        printf("%d\n",ans);    }    return 0;}

由此可见,KMP的next数组的博大精深呐!!

0 0