problem
给定一个字符串 S S S,求出形如 A B A ABA ABA 的子串数量( ∣ A ∣ ≥ k |A|\geq k ∣A∣≥k, ∣ B ∣ ≥ 1 |B|\geq 1 ∣B∣≥1)。
数据范围: ∣ S ∣ ≤ 1.5 × 1 0 4 |S|\le 1.5\times 10^4 ∣S∣≤1.5×104, 1 ≤ k ≤ 100 1\le k \le 100 1≤k≤100。
solution
可以先做一下「NOI 2014」动物园。
如果我们枚举 A A A 的左端点 l l l(令 ∣ S ∣ = r |S|=r ∣S∣=r),那么对于 ( l , r ] (l,r] (l,r] 的位置 i i i,看是否满足:
- A A A 是 [ l , i ] [l,i] [l,i] 的公共前后缀。
- 若 A A A 串长是 L L L,则 2 L + 1 ≤ i − l + 1 2L+1\le i-l+1 2L+1≤i−l+1。
- L ≥ k L\geq k L≥k。
诶除了 3 3 3 其他的不就是那道题吗,而 3 3 3 好像也只需要特判一下求出 A A A 串长 ≥ k \geq k ≥k 就可以了。
那这道题就做完啦。
时间复杂度
O
(
n
2
)
O(n^2)
O(n2),但是能过。
code
#include<bits/stdc++.h>
#define N 15005
using namespace std;
char S[N];
int n,k,ans,nxt[N];
int calc(char *S,int l,int res=0){
for(int i=2,j=0;i<=l;++i){
while(j&&S[i]!=S[j+1]) j=nxt[j];
j+=(S[i]==S[j+1]),nxt[i]=j;
}
for(int i=2,j=0;i<=l;++i){
while(j&&S[i]!=S[j+1]) j=nxt[j];
j+=(S[i]==S[j+1]);
while((j<<1)>=i) j=nxt[j];
if(j>=k) res++;
}
return res;
}
int main(){
scanf("%s%d",S+1,&k),n=strlen(S+1);
for(int i=0;i<n;++i) ans+=calc(S+i,n-i);
printf("%d\n",ans);
return 0;
}