1. 程式人生 > >3336(KMP next陣列意義,水題)

3336(KMP next陣列意義,水題)

Count the string

It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example:  s: "abab"  The prefixes are: "a", "ab", "aba", "abab"  For each prefix, we can count the times it matches in s. So we can see that prefix "a" matches twice, "ab" matches twice too, "aba" matches once, and "abab" matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For "abab", it is 2 + 2 + 1 + 1 = 6.  The answer may be very large, so output the answer mod 10007. 

Input

The first line is a single integer T, indicating the number of test cases.  For each case, the first line is an integer n (1 <= n <= 200000), which is the length of string s. A line follows giving the string s. The characters in the strings are all lower-case letters. 

Output

For each case, output only one number: the sum of the match times for all the prefixes of s mod 10007.

Sample Input

1
4
abab

Sample Output

6

題意:

在一個字串中找到每個字首在字串的出現次數,求所有前綴出現次數之和。

思路:

next陣列的意義就是該字串字尾的最大匹配個數  (匹配的為該字串的字首,且這個匹配不能為本身)

第i個字元結尾的字尾的最大匹配全部遍歷一邊,就可找出每個以第i個字元結尾的字首字串,然後遍歷每個i即可找出以所有字元結尾的前綴出現次數

如果還不懂,請看最後.

#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const int MOD=1e4+7;
int net[maxn],res[maxn];
char str[maxn];
void get_next(char *p,int *net)
{
    int lp=strlen(p);
    int j=0,k=-1;
    net[0]=-1;
    while(j<lp)
    {
        if(k==-1||p[j]==p[k])
        {
            net[++j]=++k;
        }
        else
            k=net[k];
    }
}
int Solve(char *s)
{
    int ls=strlen(s);
    get_next(s,net);
    int k;
    int ans=ls;
    for(int i=ls;i;--i)
    {
        k=net[i];
        while(k>0)
        {
            ans=(ans+1)%MOD;
            k=net[k];
        }
    }
    return ans;
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        scanf("%s",str);
        printf("%d\n",Solve(str));
    }
}

根據求next陣列的過程即可理解next陣列的意思

next[j]=k,代表如果匹配下標為j 的字串失配時應該與下標為k處開始匹配,即以j-1結尾長度為k(字尾) 與 0開頭長度為k(字首)的字串相等,且此時k是這個滿足條件中最大的!

畫個圖

next[16]=14既代表文字串與該模式串下標為16的失配時應該從下標14開始繼續匹配,同時也代表前16個字串的最大匹配字尾為14(前14個字元是16個字元的字尾) 

一直遍歷k=net[k]就可以得到該模式串的所有匹配字尾的個數直至k=0結束