字符分身
解题思路
这道题目要求我们对于每一个可能的特殊字符(a-z),模拟字符串的破译过程,并找出破译后字符串的第K个字符。如果破译后的字符串长度小于K,则输出'*'。
关键点分析
-
特殊字符的作用:当遇到连续x个特殊字符时,会将后面x个字符(或剩余所有字符)复制x次。
-
破译过程:我们需要模拟字符串的破译过程,计算在每种特殊字符情况下,字符串如何被扩展。
-
高效计算:由于n和K可能很大(1e6和1e9),我们需要避免实际构建整个破译后的字符串,而是通过数学计算来确定第K个字符。
代码注释
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n, k;
string s, tmp, ans(26,'*'); // ans初始化为26个'*',对应a-z的结果
int main(){
cin>>n>>k;
cin>>s;
// 对每个可能的特殊字符(a-z)进行处理
for(char ch='a'; ch<='z'; ch++){
ll lens = 0; // 当前已处理的字符长度
bool found = 0; // 标记是否找到第K个字符
// 遍历原字符串
for(int i=0;i<n;){
// 当前字符不是特殊字符
if(s[i] != ch){
lens++;
// 如果当前长度已经达到K,记录结果并跳出循环
if(lens >= k){
ans[ch-'a'] = s[i];
found = 1;
break;
}
i++;
continue;
}
// 当前字符是特殊字符,计算连续出现的次数cnt
int cnt = 0;
while(i<n && s[i]==ch){
cnt++; i++;
}
// 计算可以复制的字符数量(取min(cnt, 剩余字符数))
int copy_lens = min(cnt, n-i);
string copy_str = s.substr(i,copy_lens);
i += copy_lens;
// 计算复制后的总增加长度:copy_str.size() * cnt
ll add_lens = copy_str.size() * cnt;
// 如果加上这部分长度后超过K,计算第K个字符的位置
if(lens + add_lens >= k){
ll pos = k - lens - 1; // 转换为0-based索引
ans[ch-'a'] = copy_str[ pos % copy_str.size() ];
found = 1;
break;
}
lens += add_lens;
}
}
cout<<ans;
return 0;
}
算法思路
-
初始化结果数组ans:初始时所有字符的结果都是'*',表示默认情况下破译后的字符串长度不足K。
-
遍历每个可能的特殊字符(a-z):
- 初始化当前长度lens:记录在破译过程中已经处理的字符数量。
- 遍历原字符串s:
- 遇到非特殊字符:直接增加lens,并检查是否达到K。
- 遇到特殊字符:计算连续出现的次数cnt,然后复制后面min(cnt,剩余字符数)的字符cnt次。计算这部分复制后的总长度,并检查是否覆盖了第K个字符。
- 如果覆盖了第K个字符,则通过数学计算确定该字符在复制字符串中的位置。
- 如果没有覆盖,则继续处理后续字符。
-
输出结果:对于每个特殊字符,输出对应的第K个字符或'*'。
这种方法避免了实际构建整个破译后的字符串,而是通过数学计算高效地确定第K个字符的位置,适用于大规模数据。