题目:
资源限制
时间限制:1.0s 内存限制:256.0MB
样例输入
ababc
样例输出
21
样例说明
子串 f值
a 1
ab 2
aba 1
abab 0
ababc 1
b 1
ba 2
bab 1
babc 2
a 1
ab 2
abc 3
b 1
bc 2
c 1
思路:
此处思路是从b站中 《2021蓝桥杯直播公开课》中得来的。如果有不懂的同学可以去看一下老师讲的。视频播放地址:https://www.bilibili.com/video/BV1az4y1178E 从48分钟开始看即可。
这里不用暴力法的原因是暴力法的复杂度为n^2.运行超时。这里的思路是从字串的列看,一共有n列,每一列对应一个字符。那么这个字符在一列中的字串中符合条件的总数是:(该字符相同字符的上一个位置 - 该字符的位置)* (该字符相同字符的下一个位置 - 该字符的位置)。例如:下图中的第四个字符B。对应的四个是 AB,ABC,B,BC
所以难点是:怎么求该字符相同字符的上一个位置和下一个位置。具体代码中有解释。
代码:
#include <iostream>
using namespace std;
string str;
int last[26];//用于存放同一个字符的最后一个位置
int pre[100005];//用于求取每个字符的相同字符的上一个位置
int next[100005];//用于求取每个字符的相同字符的下一个位置
//复杂度为 n
int main()
{
cin>>str;//输入一个字符串
int ans = 0;//存放结果
int n = str.size();//计算字符串的长度
for(int i=0;i<26;i++) last[i] = -1;//全都初始化为-1
//这个for循环是从前往后
for(int i = 0;i<n;i++)
{
int x = str[i] - 'a';//x的值对应某个字符(某个小写字母)
pre[i] = last[x];
last[x] = i;//首先假设 x 所对应的字符是 e ,那么last[x]表示字符e最后出现的位置(位置为i),且一直在更新。
//所以下次循环中 pre[i]存放的是 本次循环 的e的位置,所以 pre[i]存放的就是最新的e的位置的上一个位置。
//所以以此类推,pre[]存放的就是每个字符某个位置的上一个位置
}
for(int i=0;i<26;i++) last[i] = n;
//这个循环是从后向前
for(int i=n-1;i>=0;i--)
{
int x = str[i] - 'a';
next[i] = last[x];
last[x] = i;//此处的解释参考上面pre[]
}
//这个循环就是求结果
for(int i =0;i<n;i++)
{
// (i - pre[i]) * (next[i] - i)是一个排列组合问题,
ans += (long long)(i - pre[i]) * (next[i] - i);
}
cout<<ans<<endl;
return 0;
}
运行结果: