「BZOJ 3620」似乎在梦中见过的样子

传送门


problem

给定一个字符串 S S S,求出形如 A B A ABA ABA 的子串数量( ∣ A ∣ ≥ k |A|\geq k Ak ∣ B ∣ ≥ 1 |B|\geq 1 B1)。

数据范围: ∣ S ∣ ≤ 1.5 × 1 0 4 |S|\le 1.5\times 10^4 S1.5×104 1 ≤ k ≤ 100 1\le k \le 100 1k100


solution

可以先做一下「NOI 2014」动物园

如果我们枚举 A A A 的左端点 l l l(令 ∣ S ∣ = r |S|=r S=r),那么对于 ( l , r ] (l,r] (l,r] 的位置 i i i,看是否满足:

  1. A A A [ l , i ] [l,i] [l,i]公共前后缀
  2. A A A 串长是 L L L,则 2 L + 1 ≤ i − l + 1 2L+1\le i-l+1 2L+1il+1
  3. L ≥ k L\geq k Lk

诶除了 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值