题解:P9244 [蓝桥杯 2023 省 B] 子串简写
题意
给定一个长度为 $ n $ 的字符串 $ S $,统计满足以下条件的子串数量:
- 子串的首字符为 $ c_1 $;
- 子串的尾字符为 $ c_2 $;
- 子串的长度大于等于 $ k $。
思路
法一:二分
设字符串的长度为 \(n\),记两个特定字符为 $ c_1 $ 与 $ c_2 $。定义数组
\[P_{c_1}=\{\,i\in\{1,2,\dots,n\}\mid \text{字符串的第 \(i\) 个字符为 } c_1\,\}
\]
和
\[P_{c_2}=\{\,j\in\{1,2,\dots,n\}\mid \text{字符串的第 \(j\) 个字符为 } c_2\,\}
\]
注意到 $ P_{c_1} $ 与 $ P_{c_2} $ 中的元素均按从小到大排列。
令 \(N(i)=\{\,j\in P_{c_2}\mid j\ge i+k\,\}\)。
由于 $ P_{c_2} $ 为递增序列,令 $ j_0 $ 为 $ P_{c_2} $ 中第一个满足 $ j_0\ge i+k $ 的元素,则从 $ j_0 $ 开始所有元素均属于 $ N(i) $ ,其个数为 $ |N(i)| $ 。
因此,最终答案
\[ans=\sum_{i\in P_{c_1}}|N(i)|
\]
在实际求解中,可利用二分查找在 $ P_{c_2} $ 中确定每个 $ i $ 对应的 $ j_0 $,因此整体时间复杂度为 $ O(n\log n) $,可 AC 本题。
#include <iostream>
#include <vector>
#define int long long
using namespace std;
string S;
char c1, c2;
int k;
vector<int> pos_c1, pos_c2;
signed main()
{
cin.tie(0)->sync_with_stdio(0);
cin >> k >> S >> c1 >> c2;
for (int i = 0; i < S.size(); i++) {
if (S[i] == c1) pos_c1.push_back(i);
if (S[i] == c2) pos_c2.push_back(i);
}
int ans = 0;
for (auto it : pos_c1) {
ans += pos_c2.end() - lower_bound(pos_c2.begin(), pos_c2.end(), it + k - 1);
}
cout << ans;
return 0;
}
法二:单调队列
在法一的启发下,使用队列表示 $ P_{c_1} $ 及 $ P_{c_2} $。对于每个 $ i\in P_{c_1} $,定义阈值 $ T=i+k-1 $。
考虑 $ P_{c_2} $ 的递增顺序,对于每个 $ i $,将队列 $ P_{c_2} $ 中的不满足 \(j\ge T\) 的队首元素 $ j $ 舍去。设舍去操作后剩下的 $ P_{c_2} $ 中的元素个数为 $ |P_{c_2}(i)| $。则当前以 $ i $ 为首字符的合法组合即有 $ |P_{c_2}(i)| $ 个,最终答案 $ ans $ 为:
\[ans=\sum_{i\in P_{c_1}}|P_{c_2}(i)|
\]
由于在整个过程中,每个 $ P_{c_2} $ 的元素最多被处理一次,故该方法的时间复杂度为 $ O(n) $。
#include <iostream>
#include <queue>
#define int long long
using namespace std;
string S;
char c1, c2;
int k;
queue<int> pos_c1, pos_c2;
signed main()
{
cin.tie(0)->sync_with_stdio(0);
cin >> k >> S >> c1 >> c2;
for (int i = 0; i < S.size(); i++) {
if (S[i] == c1) pos_c1.push(i);
if (S[i] == c2) pos_c2.push(i);
}
int ans = 0;
while (!pos_c1.empty()) {
int top = pos_c1.front();
pos_c1.pop();
while (!pos_c2.empty() and pos_c2.front() < top + k - 1) pos_c2.pop();
ans += pos_c2.size();
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号