Count the string HDU - 3336
如果直接枚举字符串前缀的子串,再将子串赋值到一个新串,就会O(n^2)超时,因此必须考虑优化
正确思路:
通过观察规律,我们可以发现当出现前缀在字符串出现次数为1的时候,后面包括这个前缀的新串,在字符串的出现次数也为1,经此优化即可
思路2:
根据ne数组计数,当ne[i]!=0时,ans++,其意义为以i为结尾的后缀与ne[i]结尾的后缀相同,那么以ne[i]为结尾的前缀在以i结尾的字符串种还会出现一次.
坑点:
请不要忘记取余,每个ans变化的地方都要取余
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int N = 200010;//不剪枝直接暴力枚举,光枚举时间复杂度是O(n^2),必定TLE,所以需要优化 6 const int M = 10007; 7 char a[N],p[N]; 8 int ne[N]; 9 int main() 10 { 11 int t; 12 scanf("%d",&t); 13 while(t--) 14 { 15 int len,ans = 0,cnt = 0; 16 scanf("%d%s",&len,a+1); 17 for(int i=1;i<=len;i++){ 18 int idx = 1; 19 if(cnt==1){ 20 ans= (ans+1)%M; continue; 21 }else cnt = 0; 22 while(idx<=i) 23 { 24 p[idx] = a[idx];//赋值 25 idx++;//枚举前缀 26 } 27 for(int k=2,j=0;k<=i;k++){//求next数组 28 while(j&&p[k]!=p[j+1]) j = ne[j]; 29 if(p[k]==p[j+1]) j++; 30 ne[k] = j; 31 } 32 for(int k=1,j=0;k<=len;k++){//匹配主串与模式串 33 while(j&&a[k]!=p[j+1]) j = ne[j]; 34 if(a[k]==p[j+1]) j++; 35 if(j==i){ 36 ans = (ans+1)%M; j = ne[j]; cnt++; 37 } 38 } 39 } 40 printf("%d\n",ans); 41 } 42 return 0; 43 }
2021.3.7 二刷完全没想到思路...