hdu 3336 Count the String

Count the string

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 5   Accepted Submission(s) : 3

Font: Times New Roman | Verdana | Georgia

Font Size:  

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



看了喵呜的解题报告才知道这么做的:

这题是KMP的变形题,主要是了解next数组的用法。

题意是,给一串字符串,问这串字符串所有的前缀总共在这个字符串中出现了几次。

已经有了next数组,next[i]=j表示最大的j使得0~j==i-j~i,因此,对于样例abab,则有

       0   1   2   3

b[]  a    b   a   b

p[]  -1  -1  0   1

对于4个前缀:

a

ab

aba

abab

设dp[i]表示子串b[0~i]共含有以b[i]为结尾的前缀的数目,则以b[i]结尾的前缀数就是自己本身加上以b[p[i]]结尾的前缀数,也就是例如i=2

则有:

a

aba这两个前缀,其中a就是b[p[i]]结尾的前缀。


View Code
 1 #include <iostream>
 2 #include <stdio.h>
 3 using namespace std;
 4 
 5 int dp[200005];
 6 char b[200005];
 7 int p[200005];
 8 int n;
 9 
10 int find()
11 {
12     int ans=1;
13     int i,j;
14     dp[0]=1;
15     j=-1;
16     p[0]=-1;
17     for(i=1;i<n;i++)
18     {
19         while(j>=0 && b[j+1]!=b[i]) j=p[j];
20         if(b[j+1]==b[i]) j++;
21         if(j>=0) dp[i]=(dp[j]+1)%10007;        // 出去这两行就是原来简单的KMP 就pre数组。
22         else  dp[i]=1;                            //
23         p[i]=j;
24         ans=(ans+dp[i])%10007;
25     }
26     return ans;
27 }
28 
29 int main()
30 {
31     int i,j,t;
32     scanf("%d",&t);
33     while(t--)
34     {
35         scanf("%d",&n);
36         scanf("%s",b);
37         printf("%d\n",find());
38     }
39     //system("pause");
40     return 0;
41 }

对于这一题还有个比较耗时间的做法:

1、首先确定下这个字符串的首个字母,然后从第二个开始搜起
当遇到和首字符一样的时候,就从该字母开始和这个字符串的首
字符开始进行比较,知道出现不一样为止,此时相同的个数就
加到总数上。
2、不一样的话就从和首个字符一样的位置的下一个字符开始。
然后和1步骤差不多,就是这个字符和首个字符往后走,遇到不
一样又重复这个步骤。。。
 
代码如下:
View Code
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 using namespace std;
 5 
 6 char str[200005];
 7 
 8 int main()
 9 {
10     int i,j,n,sum;
11     int t;
12     scanf("%d",&t);
13     while(t--)
14     {
15         scanf("%d",&n);
16         sum=n;
17         sum=sum%10007;
18         scanf("%s",str);
19         for(i=1;i<n;i++)
20         {
21             if(str[i]==str[0])
22             {
23                 for(j=i;j<n;j++)
24                 {
25                     if(str[j]!=str[j-i])
26                         break;
27                 }
28 
29                 sum+=j-i;
30                 sum=sum%10007;
31             }
32         }
33         printf("%d\n",sum);
34     }
35     return 0;
36 }
原文地址:https://www.cnblogs.com/shenshuyang/p/2607665.html