HDU 3336 KMP

Count the string

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 11954    Accepted Submission(s): 5545


Problem Description
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
 

Author
foreverlin@HNU
 

Source


题目大意

给定一个字符串,求着个字符串所有的前缀在字符串中出现的总次数
比如样例的
abab
前缀分别是a,ab,aba,abaa,在母串中出现的次数为2,2,1,1,所以答案是6

解题思路

如果每一个前缀我们都去挨个匹配母串的话,很显然我们将会面临超时的问题,所以如果有好好的学KMP的话,我们会联想到的是KMP里面的NEXT数组,NEXT数组记录的是要跳转的位置,既然能跳转,那么就一定说明当前位置的前方有一段字符串是和前缀相同的,所以问题这里就变得简单了,只要NEXT处理一遍就可以了,如果NEXT存在,那么答案(初始化答案为n)加一就可以了.
如果你这么做了,那么你会AC,但是你的解法并不正确,或者可以说你对NEXT数组的理解不够深刻,本题数据很水所以导致有的问题你没有处理到也可以AC
这里我举一个例子 asasa,正确答案是9,但是如果按照上述做法是8
为什么会这样呢,我们把前缀取出来分别是a,as,asa,asas,asasa
  他们的个数分别是3,2,2,1,1,若果按照原来的算法它的个数分别是2,2,2,1,1
        这里我把NEXT的值列出来NEXT[0] = -1,NEXT[1] = 0,NEXT[2] = 0,NEXT[3] = 1,NEXT[4] = 2,NEXT[5] = 3,
        原因出在哪里呢?我们在计算NEXT数组的时候没有进行回溯就造成了这个问题,因为NEXT[5] = 3,但是NEXT[3] = 1,
       这里可以进行回溯,这说明什么?说明前缀不止一个,当前前缀还包含若干个小前缀。
   理解了这个本题就做完了
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 2000000 + 10;
char q[maxn],p[maxn];
int ne[maxn];
int getnext(char * a){
  int lena = strlen(a);
  int i = -1;
  int j = 0;
  ne[0] = -1;
  while(j < lena){
    if(i == -1 || a[i] == a[j]){
        i++;
        j++;
        ne[j] = i;
    }
    else{
        i = ne[i];
    }
  }
}
int main(){
  int  T;
  scanf("%d", &T);
  while(T--)
 {
    int n;
    scanf("%d %s", &n, q);
    int tot = n;
    memset(ne, 0, sizeof(ne));
    getnext(q);
    for(int i = 1; i <= n; i++){
        if(ne[i] > 0)
        {
            int an = i;
            while(ne[an] > 0){
                  tot = (tot + 1) % 10007;
                  an = ne[an];
            }
        }
    }
    printf("%d\n", tot);
 }
  return 0;
}


发布了69 篇原创文章 · 获赞 58 · 访问量 5万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章