题解: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) \]

posted @ 2025-10-26 21:15  fengjunxiao2014  阅读(5)  评论(0)    收藏  举报