【题目链接】
【前置技能】
- 后缀数组
【题解】
- 把原字符串复制倍长,进行后缀排序,然后按照要求输出即可。
【代码】
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 200010
using namespace std;
char s[MAXN];
int n, rnk[MAXN], sa[MAXN];
template <typename T> void chkmin(T &x, T y){x = min(x, y);}
template <typename T> void chkmax(T &x, T y){x = max(x, y);}
template <typename T> void read(T &x){
x = 0; int f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
void getsa(){
static int x[MAXN], y[MAXN], rk[MAXN], cnt[MAXN];
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; ++i)
++cnt[(int)s[i]];
for (int i = 1; i <= 256; ++i)
cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i)
sa[cnt[(int)s[i]]--] = i;
rnk[sa[1]] = 1;
for (int i = 2; i <= n; ++i)
rnk[sa[i]] = rnk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]);
for (int k = 1; rnk[sa[n]] != n; k <<= 1){
for (int i = 1; i <= n; ++i)
x[i] = rnk[i], y[i] = (i + k <= n) ? rnk[i + k] : 0;
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; ++i)
++cnt[y[i]];
for (int i = 1; i <= n; ++i)
cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i)
rk[cnt[y[i]]--] = i;
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; ++i)
++cnt[x[i]];
for (int i = 1; i <= n; ++i)
cnt[i] += cnt[i - 1];
for (int i = n; i >= 1; --i)
sa[cnt[x[rk[i]]]--] = rk[i];
rnk[sa[1]] = 1;
for (int i = 2; i <= n; ++i)
rnk[sa[i]] = rnk[sa[i - 1]] + (x[sa[i]] != x[sa[i - 1]] || y[sa[i]] != y[sa[i - 1]]);
}
}
int main(){
scanf("%s", s + 1);
n = strlen(s + 1);
for (int i = 1; i <= n; ++i)
s[i + n] = s[i];
n = n * 2;
getsa();
for (int i = 1; i <= n; ++i){
if (sa[i] > n / 2) continue;
putchar(s[sa[i] + n / 2 - 1]);
}
puts("");
return 0;
}