字符串

时间限制:1000MS
内存限制:128000KB

题目描述
小熊有一个由小写英文字母组成的字符串s = s1s2…sn。小熊想要计算s中有多少子串包含字符串“bear”,也就是找出满足字符串x(i, j)= sisi+1…sj 包含至少一个字符串“bear”的 (i, j)对数(1≤i≤j≤n)。
字符串x(i, j)包含字符串“bear”定义为存在一个整数k(i≤k≤j-3),满足sk=b,sk+1=e,sk+2=a,sk+3=r。
请帮助小熊解决这个问题。

输入
输入共1行,包含一个非空字符串s。数据保证字符串s中只包含小写英文字母。

输出
输出共1行,包含一个整数,表示这个问题的答案。

输入样例
bebearar

输出样例
9

说明

【输入输出样例说明】
符合条件的9对(i, j)为:(1,6),(1,7),(1,8),(2,6),(2,7),(2,8),(3,6),(3,7),(3,8)。

【数据说明】
对于50%的数据,1≤n≤200。
对于100%的数据,1≤n≤3000。

解题思路

这题就是用一个字符串来模拟题意
一开始,我的思路是

找到bear,算出包含这个bear的序列有多少个 (这里用之前讲的:用左边最多能延长多少格(这里是b的位置-0+1)乘 右边最多能延长多少格(这里是字符串的长度-r的位置+1))

但是,有个问题,假如样例是这样:

abearbbbear

按照我开始的思路,就会记录两遍(1,10) 答案就不对了


所以,有了我接下来的思路

后来我发现

只需要更改0(0为上面式子中的0)(也就是最左边能延长的格子),不用更改右边最多能延长多少格

因为,拿刚刚的样例

abearbbbear

第一个bear不用更改有:(0,4)(0,5)(0,6)(0,7)(0,8)(0,9)(0,10)(1,4)……(1,10)这几种情况
到了第二个bear,将0更改为第一个bear中e的位置,就有:(2,9)(3,9)(4,9)(5,9)(6,9)(7,9)
没有重复,并且答案对了,为:20

下面是AC代码

AC代码

#include<cstdio>
#include<iostream>
using namespace std;
int a,o,ok,x[3005];
long long ans;
string s,s1;
int main()
{
   
	cin>>s;
	s1="bear";
	for(int i=0;i<s.size();i++)//找bear
	 if(s[i]=='b'&&s.size()-i-1>=3)//判断越界
	 {
   
		ok=1;
		for(int j=i;j<=i+3;j++)
	     if(s[j]!=s1[j-i]){
   ok=0;break;}
		if(ok==1)x[++o]=i;//记录起始点
	 }
	a=0; //a为最左端能延长的格子的位置
	for(int i=1;i<=o;i++)
	{
   
		if(i>=2)a=x[i-1]+1;//更改
		ans+=(x[i]-a+1)*(s.size()-1-(x[i]+3)+1);//公式
	} 
	printf("%lld",ans);
	return 0;
}

下面附本次比赛的其它题目

2020.9.12 SSL普及组模拟(第1题)(字符串)
2020.9.12 SSL普及组模拟(第2题)(序列)(dp)
2020.9.12 SSL普及组模拟(第3题)(游戏)(bfs20分)(求找问题)
2020.9.12 SSL普及组模拟(第4题)(树)(暴力邻接表80)
2020.9.12 SSL普及组模拟(总结)

谢谢