Description
已知一个字符串S,求它有多少个形如A+B+A的子串(len(A)>=k,len(B)>=1 )。
Input
第一行一个字符串,第二行一个数 k。
Output
仅一行一个数,表示满足条件的子串数。
Sample Input
aaaaa
1
Sample Output
6
HINT
对于 100%的数据:n<=15000 , k<=100,且字符集为所有小写字母。
Solution
这道题时限15s,明显O(n2)可以过。那么如果枚举某一端形成新的子串,用kmp的思想去处理的话,就可以过了。
那具体要如何处理这个子串呢?假设我们枚举左端点l,s长度为r,则形成的新子串为s[l...r]。
由题意我们可以知道,如果s[l...i]=s[j-i+l...j]且(i-l+1)>=k且l-1+(i-l+1)×2+1<=j,那么s[l...j]就是一个满足条件的子串,那么这道题就明显和Noi2014动物园很像了。
如果直接暴力用next[]找满足条件的前缀,实现会变成O(n3)。
所以这个地方得继续用kmp的思想:当发现现在的i不满足条件时,可以用next[]向前寻找满足条件的i。
这样的话,每次都是从满足(j-1)的条件的i开始寻找,于是时间复杂度就压到了O(n2)。
1 #include<set> 2 #include<cmath> 3 #include<ctime> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<vector> 8 #include<cstring> 9 #include<cstdlib> 10 #include<iostream> 11 #include<algorithm> 12 #define N 15002 13 using namespace std; 14 int next[N],n,k,ans; 15 char a[N]; 16 inline void get_next(char a[]){ 17 for(int i=2,j=0;a[i];i++){ 18 while(j&&a[i]!=a[j+1]) j=next[j]; 19 j+=(a[i]==a[j+1]); 20 next[i]=j; 21 } 22 for(int i=2,j=0;a[i];i++){ 23 while(j&&a[i]!=a[j+1]) j=next[j]; 24 j+=(a[i]==a[j+1]); 25 while(j&&j*2>=i) j=next[j]; 26 if(j>=k) ans++; 27 } 28 } 29 inline void init(){ 30 scanf("%s%d",a+1,&k); 31 n=strlen(a+1);n-=(k<<1); 32 for(int i=0;i<n;i++) 33 get_next(a+i); 34 printf("%d",ans); 35 } 36 int main(){ 37 freopen("dream.in","r",stdin); 38 freopen("dream.out","w",stdout); 39 init(); 40 fclose(stdin); 41 fclose(stdout); 42 return 0; 43 }