专栏文章
题解:P13270 【模板】最小表示法
P13270题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miowgeux
- 此快照首次捕获于
- 2025/12/03 02:16 3 个月前
- 此快照最后确认于
- 2025/12/03 02:16 3 个月前
最小表示法的概念
最小表示法是一种用于处理字符串循环同构问题的算法。当一个字符串可以通过循环移位得到另一个字符串时,这两个字符串被称为循环同构。例如,字符串
"abc" 的循环同构字符串包括 "abc" 、 "bca" 和 "cab" 。最小表示法就是找到这些循环同构字符串中字典序最小的那个。前置知识
- 字符串循环移位:将字符串的前 个字符移到字符串的末尾,形成新的字符串。
- 字典序:字符串比较的一种方式,按字符的 ASCII 码值逐位比较。
算法证明
我们需要证明:算法最终返回的起点一定是所有可能起点中字典序最小的。
证明:我们运用反证法。假设存在 是最小表示的起点,则从 开始的字符串 应小于所有其他起点的字符串。
但由于 且 ,从 开始的字符串前缀与从 开始的字符串前缀有重叠:。 而已知 ,且 的位置与 无关 ,因此从 开始的字符串会大于从 开始的字符串(因为 的前缀是 的后缀,而 整体大于 ),与 “ 是最小起点” 矛盾。因此 中的所有起点均不可能是最小表示。
算法的时间复杂度由 的总移动次数决定。三者的总移动次数不超过 ,因此整体复杂度为 。完全可以处理题目给的数据范围。
证明:我们运用反证法。假设存在 是最小表示的起点,则从 开始的字符串 应小于所有其他起点的字符串。
但由于 且 ,从 开始的字符串前缀与从 开始的字符串前缀有重叠:。 而已知 ,且 的位置与 无关 ,因此从 开始的字符串会大于从 开始的字符串(因为 的前缀是 的后缀,而 整体大于 ),与 “ 是最小起点” 矛盾。因此 中的所有起点均不可能是最小表示。
算法的时间复杂度由 的总移动次数决定。三者的总移动次数不超过 ,因此整体复杂度为 。完全可以处理题目给的数据范围。
思路
那我们该如何去求字符串的最小表示呢?
我们先扩展字符串,相当于把它再复制一遍然后加到原来字符串的后面,这样做是为了便于处理循环移位。
接下来我们初始化指针。令
然后比较
最终, 和 中较小的那个就是最小表示的起始位置。
输出从起始位置截取长度为 的子串,即为所求的最小表示。
我们先扩展字符串,相当于把它再复制一遍然后加到原来字符串的后面,这样做是为了便于处理循环移位。
接下来我们初始化指针。令
i = 0 和 j = 1 分别表示两个可能的最小表示的起始位置。
令 k = 0 表示当前比较的长度。然后比较
s[i + k] 和 s[j + k]:
如果相等, 增加 ,继续比较下一个字符。
当它们不相等时:
如果 s[i + k] 大于 s[j + k],说明从 开始的子串不可能是最小表示,将 移动到 。
反之,将 移动到 。
确保 和 不相等,如果相等则将 加 。最终, 和 中较小的那个就是最小表示的起始位置。
输出从起始位置截取长度为 的子串,即为所求的最小表示。
code
CPP#include <bits/stdc++.h>
using namespace std;
int n;
string s;
int main(){
cin>>n>>s;
s=s+s; // 复制字符串以处理循环移位
int i=0,j=1,k=0;
while(i<n&&j<n&&k<n){//开始处理循环移位
if(s[i+k]==s[j+k]){
k++;
}
else{
if(s[i+k]>s[j+k]){
i=i+k+1;
}
else{
j=j+k+1;
}
if(i==j){
j++;
}
k=0;
}
}
int start=min(i,j);//确定最小表示的起始位置
cout<<s.substr(start,n); //直接输出
return 0;//朴实无华的结尾
}
如果觉得写的好的请点个赞再走呗。
管理大大求过 QAQ 。
管理大大求过 QAQ 。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...