[JSOI 2007] 字符加密
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1031
[算法]
将字符串倍长 , 构建后缀数组 , 然后按要求输出即可
时间复杂度 : O(NlogN)
[代码]
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 10; typedef long long ll; typedef long double ld; int n; int cnt[MAXN] , sa[MAXN] , rk[MAXN] , x[MAXN] , y[MAXN]; char s[MAXN]; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void get_sa() { memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= 2 * n; i++) ++cnt[(int)s[i]]; for (int i = 1; i <= 256; i++) cnt[i] += cnt[i - 1]; for (int i = 2 * n; i >= 1; i--) sa[cnt[s[i]]--] = i; rk[sa[1]] = 1; for (int i = 2; i <= 2 * n; i++) rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]); for (int k = 1; rk[sa[2 * n]] != 2 * n; k <<= 1) { memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= 2 * n; i++) x[i] = rk[i] , y[i] = (i + k <= 2 * n) ? rk[i + k] : 0; for (int i = 1; i <= 2 * n; i++) ++cnt[y[i]]; for (int i = 1; i <= 2 * n; i++) cnt[i] += cnt[i - 1]; for (int i = 2 * n; i >= 1; i--) rk[cnt[y[i]]--] = i; memset(cnt , 0 , sizeof(cnt)); for (int i = 1; i <= 2 * n; i++) ++cnt[x[i]]; for (int i = 1; i <= 2 * n; i++) cnt[i] += cnt[i - 1]; for (int i = 2 * n; i >= 1; i--) sa[cnt[x[rk[i]]]--] = rk[i]; rk[sa[1]] = 1; for (int i = 2; i <= 2 * n; i++) rk[sa[i]] = rk[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[n + i] = s[i]; get_sa(); for (int i = 1; i <= 2 * n; i++) { if (sa[i] + n - 1 < 2 * n) putchar(s[sa[i] + n - 1]); } return 0; }