解题思路
——因为一个数组开小了调了1个小时,我无语了啊啊啊啊啊…TOT
这道题因为数据不大,可以直接跑 n 2 n^2 n2。
考虑枚举左端点,设左端点为 l , S = C [ l , ∣ C ∣ ] l,S=C[l,|C|] l,S=C[l,∣C∣],那么对字符串S跑一次 K M P KMP KMP。
然后在统计过程中,假设现在在i位置,则 S [ 1 , j ] = S [ i − j + 1 , i ] S[1,j]=S[i-j+1,i] S[1,j]=S[i−j+1,i]。如果 j ∗ 2 > = i j*2>=i j∗2>=i,那么令j=p[j],此时 A [ 1 , j ] = a [ i − j + 1 , i ] , j A[1,j]=a[i-j+1,i],j A[1,j]=a[i−j+1,i],j不断沿指针回跳,直到 j ∗ 2 < i j*2<i j∗2<i。然后再判断j是否大于等于k,如果是,那么累加答案。
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
char s[20010],c[20010];
int ans,j,k,l,len,m,p[20010];
int main() {
scanf("%s",c+1);
scanf("%d",&k);
len=strlen(c+1);
for(register int t=1; t<=len; t++) {
memset(s,0,sizeof(s));
memset(p,0,sizeof(p));
for(register int w=1;w+t-1<=len;w++)
s[w]=c[w+t-1]; //处理左端点
j=0,l=strlen(s+1);
for(register int i=2; i<=l; i++) {
while(j&&s[i]!=s[j+1])
j=p[j];
if(s[i]==s[j+1])
j++;
p[i]=j;
}
j=0;
for(register int i=1; i<=l; i++) {
while(j&&s[i]!=s[j+1])
j=p[j];
if(s[i]==s[j+1])
j++;
while((j<<1)>=i)j=p[j];
if(j>=k)ans++;
}
}
printf("%d",ans);
}