标签:
题目大意:
找到字符串中所有和前缀字符串相同的子串的个数
对于这种前缀的问题,通常通过扩展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 }
标签:
原文地址:http://www.cnblogs.com/CSU3901130321/p/4598958.html