HDU 3336 扩展kmp

 题目大意:

找到字符串中所有和前缀字符串相同的子串的个数

 

对于这种前缀的问题,通常通过扩展kmp来解决

其实吧这是我第一次做扩展kmp的题目,原来确实看过这个概念,今天突然做到,所以这个扩展kmp的模板是做到这道题直接copy的

这里用扩展kmp很好解决问题,_next[i],表示第i位开始所能匹配到的最大公共前缀长度,比如说这个长度为4,那么说明前缀1,2,3,4都出现了一次,我们只在cnt[4]++

那么最后从n到1,逆向更新cnt[i] += cnt[i+1]即可,最后得到cnt[i]就表示前缀长度为i的时候所能得到的相同的子串的个数

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 #define N 200005
 7 #define MOD 10007
 8 char s[N];
 9 int _next[N] , cnt[N];
10 
11 void get_next(char *T){// _next[i]: 以第i位置开始的子串 与 T的公共前缀
12      int i,length = strlen(T);
13      _next[0] = length;
14      for(i = 0;i<length-1 && T[i]==T[i+1]; i++);
15           _next[1] = i;
16           int a = 1;
17           for(int k = 2; k < length; k++){
18                   int p = a+_next[a]-1, L = _next[k-a];
19                   if( (k-1)+L >= p ){
20                        int j = (p-k+1)>0? (p-k+1) : 0;
21                        while(k+j<length && T[k+j]==T[j]) j++;// 枚举(p+1,length) 与(p-k+1,length) 区间比较
22                        _next[k] = j, a = k;
23                   }
24                   else _next[k] = L;
25          }
26 }
27 int main()
28 {
29    // freopen("a.in" , "r" , stdin);
30     int T;
31     scanf("%d" , &T);
32     while(T--)
33     {
34         int n;
35         scanf("%d%s" , &n , s);
36         get_next(s);
37       //  for(int i=0 ; i<n ; i++) cout<<_next[i]<<endl;
38         memset(cnt , 0 , sizeof(cnt));
39         for(int i=0 ; i<n ; i++) cnt[_next[i]]++;
40         for(int i=n-1 ; i>=1 ; i--) cnt[i]+=cnt[i+1];
41         int sum=0;
42         for(int i=1 ; i<=n ; i++) sum = (sum+cnt[i])%MOD;
43         printf("%d\n" , sum);
44     }
45     return 0;
46 }

 

你可能感兴趣的:(HDU)