[BZOJ1031][JSOI2007]字符加密Cipher
1031: [JSOI2007]字符加密Cipher
Time Limit: 10 Sec Memory Limit: 162 MB Submit: 7384 Solved: 3198 [Submit][Status][Discuss]Description
喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法
:把需要加密的信息排成一圈,显然,它们有很多种不同的读法。例如下图,可以读作:
JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0把它们按照字符串的大小排序:07JSOI 7JSOI0 I07JSO JSOI07
OI07JS SOI07J读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是
突然想出来的,那就^^)。但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?
Input
输入文件包含一行,欲加密的字符串。注意字符串的内容不一定是字母、数字,也可以是符号等。
Output
输出一行,为加密后的字符串。
Sample Input
JSOI07
Sample Output
I0O7SJ
HINT
对于100%的数据字符串的长度不超过100000。
把原串$S$复制一遍放在后面变为$SS$,求出$SS$的后缀数组,然后按序输出即可
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 200000 + 10; int sa[maxn], rank[maxn], tp[maxn], tax[maxn]; int n, m; char s[maxn]; inline void Rsort(){ for(int i = 0; i <= m; i++) tax[i] = 0; for(int i = 1; i <= n; i++) tax[rank[tp[i]]]++; for(int i = 1; i <= m; i++) tax[i] += tax[i - 1]; for(int i = n; i; i--) sa[tax[rank[tp[i]]]--] = tp[i]; } bool inline cmp(int *a, int l, int r, int w){ return a[l] == a[r] && a[l + w] == a[r + w]; } void suffix(){ m = 127; for(int i = 1; i <= n; i++){ rank[i] = s[i]; tp[i] = i; } Rsort(); for(int p, w = 1; p < n; w <<= 1, m = p){ p = 0; for(int i = n - w + 1; i <= n; i++) tp[++p] = i; for(int i = 1; i <= n; i++) if(sa[i] > w) tp[++p] = sa[i] - w; Rsort(); swap(rank, tp); p = rank[sa[1]] = 1; for(int i = 2; i <= n; i++) rank[sa[i]] = cmp(tp, sa[i], sa[i - 1], w) ? p : ++p; } } int main(){ scanf("%s", s + 1); n = strlen(s + 1); for(int i = 1; i <= n; i++) s[i + n] = s[i]; n <<= 1; suffix(); n >>= 1; for(int i = 1; i <= (n << 1); i++) if(sa[i] <= n) printf("%c", s[sa[i] + n - 1]); return 0; }