[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;
}

 

posted @ 2017-08-27 14:35  jzyy  阅读(117)  评论(0编辑  收藏  举报