[bzoj3670][2014湖北省队互测week2]似乎在梦中见过的样子

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)>=kl-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 }

转载于:https://www.cnblogs.com/AireenYe/p/5653802.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值