题目大意
给定字符串 s s s,字符 a , b a, b a,b,问字符串 s s s 中有多少个 a a a 开头 b b b 结尾的子串。
解题思路
20pts
使用二重循环枚举左端点和右端点,判断是否为 a a a 开头 b b b 结尾的字符串,是则答案加一。
100pts
数据范围较大,我们需要将时间复杂度控制在 O ( n log n ) O(n\log n) O(nlogn) 以内。
法一
我们需要找到所有 a a a 开头 b b b 结尾的字符串,那么我们可以对于每个字符 b b b,去看 b b b 的左侧有几个 a a a,那么这些 a ... b a\dots b a...b 就是合法的字符串。统计某个位置的左侧有几个字符 a a a,我们可以使用前缀和算法进行维护。
法二
我们可以去遍历整个字符串,对于每个 a a a 字符的右侧有几个字符 b b b,那么这些 a ... b a \dots b a...b 都是合法的字符串。统计某个位置之后字符 b b b 的个数,可以使用后缀和算法进行维护。
cpp
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 5e5 + 10;
int n, m;
string str;
char a, b;
int s[N];
int main()
{
cin >> m >> str >> a >> b;
n = str.size();
str = ' ' + str;
for (int i = n; i; -- i )
s[i] = s[i + 1] + (str[i] == b);
LL res = 0;
for (int i = 1; i + m - 1 <= n; ++ i )
if (str[i] == a)
res += s[i + m - 1];
cout << res << endl;
return 0;
}