题解:B4205 [常州市赛 2021] 特殊字符
前言
题目传送门
思路分析
因为数据范围较大,所以直接暴力构建字符串不仅仅会超时,还会爆空间,所以我们考虑模拟、跳过构建字符串,直接给出答案
我们对于每个特殊字符,从左向右遍历字符串:
- 若遇到一段连续的特殊字符,我们则提取出需要复制的后续字符串
- 特殊地处理一下子这串后续字符串,重复次数为连续特殊字符的数量
- 接着继续判断
- 如果第 \(K\) 个字符不落在这个范围内,正常推进即可
- 如果答案落在这个范围内,直接判断并输出
- 如果没有遍历到特殊字符,就正常推进
code
#include <bits/stdc++.h>
#define int long long // 不开longlong见祖宗
using namespace std;
int n, k;
string s;
signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);cin >> n >> k;cin >> s;// 输入// 遍历26个小写字母,检查每个字母作为特殊字符的情况for (char c = 'a'; c <= 'z'; c++){int cnt = k; // cnt: 当前还需要查找的字符位置(初始化为k)int num = 0; // num: 记录连续出现的特殊字符c的数量// 遍历字符串的每个字符(包括结尾后一位(i<=n)for (int i = 0; i <= n; i++){if (s[i] == c) // 如果当前字符是特殊字符c{num++; // 连续特殊字符计数+1}else // 如果当前字符不是特殊字符c{if (num) // 如果之前有连续的特殊字符c{// sum: 计算复制次数,取num和剩余字符数(n-i)的最小值int sum = min(num, n - i);// 如果剩余的查找位置足够大,跳过这段被复制的字符不影响结果if (cnt > sum * num) {cnt -= sum * num; // 减少cnti += sum - 1; // 跳过被复制的字符num = 0; // 重置连续特殊字符计数}else // 剩余的查找位置在当前复制段内{cnt %= sum; // 计算在该段中的位置if (!cnt) cnt = sum; // 如果余数为0,取sum// 输出该段中的第cnt个字符cout << s[i + cnt - 1];cnt = num = 0; // 重置break; // 结束当前字符的处理}}else if (i != n) // 如果没有连续的特殊字符且未到字符串末尾{cnt--; // 直接消耗一个查找位置if (cnt == 0) // 如果找到第k个字符{cout << s[i]; // 输出当前字符break; // 结束当前字符的处理}}}}if (cnt) cout << "*"; // 如果遍历完字符串仍未找到第k个字符,输出*}return 0;
}
时空复杂度分析
时间复杂度为循环次数相乘:
\[O(26\times n)
\]
空间复杂度仅仅是输入的字符串 \(s\)
\[O(n)
\]