bzoj3620似乎在梦中见过的样子
题意:
给出一个字符串,要求求出形如A+B+A的子串数量,且lenA≥k,lenB≥1。字符串长度≤15000,k≤100,所以字符长度为小写字母。
题解:
第一次写kmp的题QAQ~这题利用的是fail函数的性质:若字符串s在位置x的fail函数f[x]不为0,则prefix(s+1,s+x)的长度为f[x]的前缀和长度为f[x]的后缀相同。因此枚举每个后缀为为j,对这个后缀做kmp,再递推一个令f[i]-j+1≥k且最小的f[i]为last[x](f[i]表示i=x; while(i>=后缀位)i=f[i]得到的所有f[i]),若last[x]-j小于等于(x-j)/2则子串(j,x)合法。讲的很乱,具体看代码。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 #define INF 0x3fffffff 7 using namespace std; 8 9 char s[15100]; int l,k,next[15100],last[15100],ans; 10 int main(){ 11 //freopen("in.txt","r",stdin); 12 scanf("%s",s+1); l=strlen(s+1); scanf("%d",&k); ans=0; 13 inc(i,1,l){ 14 next[i]=i-1; last[i]=INF; 15 inc(ii,i+1,l){ 16 int j=next[ii-1]; while(j>=i&&s[ii]!=s[j+1])j=next[j]; 17 if(s[ii]==s[j+1])next[ii]=j+1;else next[ii]=j; 18 if(next[ii]-i+1<k)last[ii]=INF;else{ 19 last[ii]=min(last[next[ii]],next[ii]); 20 if(last[ii]-i+1<=(ii-i)>>1)ans++;//,printf("%d %d\n",i,ii); 21 } 22 } 23 } 24 printf("%d",ans); return 0; 25 }
20160609