题解:B4205 [常州市赛 2021] 特殊字符
题解: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; // 减少cnt
i += 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)
\]

浙公网安备 33010602011771号