2020 算法上机赛 C2 - J L星门
题目描述
2400年,XT-486 灭绝者帝国的首席科(gong)学(ju)家(ren) HolmiumTS 在花了数百年的时间探索银河系各个星系之后,终于发现了数万前曾经统一银河的超级帝国——第一联盟的最后据点, L 星门。
如果能够打开 L 星门,HolmiumTS 及整个 XT-486 来绝者帝国就将有机会了解更多宇宙的兴衰史,以让整个帝国更好的应对未来可能的危机,因此整个帝国对此高度重视。
L 星门包含了许多被第一联盟称为“石像”的锁,锁上有一个以顺时针顺序刻好的字符串环,如果把锁上代表字典序最小的字符串的起始位置对准“石像”上的开锁刻线,锁就能够被打开。
现在,HolmiumTS 命令你负责整个 L 星门的“石像”锁的解锁工作,如果你没有按时完成的话,你就会被做成罐头拿去喂海星()。
输入
第一行包含一个正整数,为数据的组数 \(T\) 。
接下来的 \(T\) 行,每行一个字符串 \(s\) ,为“石像”锁上按顺时针读出的字符串。
输出
对于每组数据,输出一行,包含一个要求的字典序最小的字符串。
输入样例
3
accbbaaa
efgabcd
xyxyxxy
输出样例
aaaaccbb
abcdefg
xxyxyxy
数据范围与约定
\(1\leq T\leq5\)
\(1\leq len(s)\leq1e5\)
字符串中只包含小写字母
提示
直接使用sort
会被卡吗?
本题不考查卡常数,助教写的两种未经任何优化的标准程序在各测试点上的最大运行时间分别为810ms和152ms,本题时间限制分别为它们的约2.5倍和约13倍,换句话说,TLE了请优先怀疑算法的时间复杂度不满足要求,而不是评测机的运行速度不够快。
本题你可能需要用到的算法:排序、分治、倍增……
分治和倍增之间的关系,和递归和递推之间的关系非常类似。
题目背景:游戏《Stellaris》,制作:Paradox Interactive
大人,食大便了.jpg,现在轮到海星吃人肉罐头了()。
做法
据说本来想出一个用来防 AK 的题,结果失败了(x
提示中提到的做法,是用倍增的方式进行排序(具体原理可以参考后缀数组)
不过,这个题目要求的输出,实际上是 字符串的最小表示
这个是可以直接 \(O(n)\) 求出来的
原理放这里了: 最小表示法
出题人最开始的想法: 后缀数组
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int q=0,w=1;char c=getchar();
while(!isdigit(c)){if(c=='-')w=-1;c=getchar();}
while(isdigit(c))q=q*10+c-'0',c=getchar();
return w*q;
}
const int N = 5e5 + 100;
int T; char s[N];
int getmin(){
int n = strlen(s);
int i = 0, j = 1, k = 0, t;
while(i < n && j < n && k < n){
t=s[(i + k) % n] - s[(j + k) % n];
if (!t) k++;
else{
if (t > 0) i += k+1;
else j += k+1;
if (i==j) j++;
k=0;
}
}
return i < j ? i : j;
}
void solve() {
int pos = getmin(), n = strlen(s);
for(int i = 1;i <= n; ++i)
printf("%c", s[pos]),
pos = (pos + 1) % n;
puts("");
}
int main() {
T = read(); while(T--) {scanf("%s", s); solve();}
return 0;
}