题目
咕咕东很聪明,但他最近不幸被来自宇宙的宇宙射线击中,遭到了降智打击,他的英语水平被归 零了!这一切的始作俑者宇宙狗却毫不知情!
此时咕咕东碰到了一个好心人——TT,TT在吸猫之余教咕咕东学英语。今天TT打算教咕咕东字母A 和字母B,TT给了咕咕东一个只有大写A、B组成的序列,让咕咕东分辨这些字母
但是咕咕东的其他学科水平都还在,敏锐的咕咕东想出一个问题考考TT:咕咕东问TT这个字符串 有多少个子串是Delicious的。
TT虽然会做这个问题,但是他吸完猫发现辉夜大小姐更新了,不想回答这个问题,并抛给了你, 你能帮他解决这个问题吗?
Delicious定义:对于一个字符串,我们认为它是Delicious的当且仅当它的每一个字符都属于一个 大于1的回文子串中。
输入输出
Input
输入第一行一个正整数n,表示字符串长度 接下来一行,一个长度为n只由大写字母A、B构成的字符串。
Output
输出仅一行,表示符合题目要求的子串的个数。
Sample Input
5
AABBB
Sample Output
6
数据规模
思路分析
这道题考试的时候理解回文子串花了一些时间,然后找规律,最后没有足够时间来完成这道题目。补题时最先想到的是暴力枚举,复杂度是O(n^2),显然后四个测试点过不去,要么考虑剪枝,要么……换个思路。
鉴于不合法的子串只有AB…B、BA……A、A……AB、B……BA这四种类型,可以考虑求出所有子串个数(n*(n-1)/2),然后减去不合法子串的个数即可。
那么如何求不合法子串的个数呢?拿AAAAB举个栗子,该字符串是典型的不合法结构,可以发现,子串AAAAB是不合法的,同理,子串AAAB、AAB、AB也是不合法的,因此,不合法子串的个数就等于字符A的个数。同理,AB……B和B……B A结构中不合法子串的个数是字符B的个数,但是要注意
,对于两种字符串衔接处的AB或BA被计算了两次,因此总数减一,得到不合法子串的个数为numA+numB-1。
具体做法:寻找连续的字符,当遇到不同字符时分段记录前后两种字符的个数。
总结反思
考场上要放平心态,找规律的题目别心急,静心思考。
AC代码
#include<iostream>
#include<string>
using namespace std;
string s;
long long n,ans=0,l=0,r=0,cnt1=0,cnt2=0,no=0;
//cnt1表示前一段字符的个数,cnt2表示后一段字符的个数,no表示不合法子串个数
int main()
{
cin>>n;
cin>>s;
ans=n*(n-1)/2;//ans初始化为总字符串个数
while(l<n){
r=l;
while(r<n-1&&s[r]==s[l]){
r++;
}
if(r==n-1&&s[r]==s[l]) break;
cnt1=r-l;//前一段字符的个数
char c=s[r];
long long tmp=r;
while(r<n-1&&s[r]==c){
r++;
}
if(r==n-1&&s[r]==c)
cnt2=r-tmp+1;
//r记录下次变化的位置,因此如果r没遍历到最后一个,
//那么长度就是r-tmp,即不包括位置r的字符
else
cnt2=r-tmp;
l=tmp;
no+=cnt1+cnt2-1;//不合法子串个数
}
ans-=no;
cout<<ans<<endl;
return 0;
}