[BZOJ1031] [JSOI2007] 字符加密Cipher (后缀数组)

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。

Source

Solution

  题意中所谓的顺序,其实就是把字符串复制一遍后的$sa$值,每个字符串的最后一个字符对应的就是$s[sa[i]+n-1]$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 char s[200005];
 4 int sa[200005], wv[2][350005], tong[200005];
 5  
 6 bool cmp(int *tmp, int x, int y, int j)
 7 {
 8     return tmp[x] == tmp[y] && tmp[x + j] == tmp[y + j];
 9 }
10  
11 void getsa(int n, int m)
12 {
13     int p = 0, *x = wv[0], *y = wv[1];
14     for(int i = 0; i < n; ++i)
15         ++tong[x[i] = s[i]];
16     for(int i = 1; i < m; ++i)
17         tong[i] += tong[i - 1];
18     for(int i = n - 1; ~i; --i)
19         sa[--tong[x[i]]] = i;
20     for(int j = 1; p != n; j <<= 1, m = p)
21     {
22         p = 0;
23         for(int i = n - j; i < n; ++i)
24             y[p++] = i;
25         for(int i = 0; i < n; ++i)
26             if(sa[i] >= j) y[p++] = sa[i] - j;
27         for(int i = 0; i < m; ++i)
28             tong[i] = 0;
29         for(int i = 0; i < n; ++i)
30             ++tong[x[y[i]]];
31         for(int i = 1; i < m; ++i)
32             tong[i] += tong[i - 1];
33         for(int i = n - 1; ~i; --i)
34             sa[--tong[x[y[i]]]] = y[i];
35         swap(x, y), p = 1, x[sa[0]] = 0;
36         for(int i = 1; i < n; ++i)
37             x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
38     }
39 }
40  
41 int main()
42 {
43     int n;
44     cin >> s;
45     n = strlen(s);
46     for(int i = 0; i < n; ++i)
47         s[i + n] = s[i];
48     getsa(n << 1 | 1, 128);
49     for(int i = 1; i <= n << 1; ++i)
50         if(sa[i] < n) cout << s[sa[i] + n - 1];
51     cout << endl;
52     return 0;
53 }
View Code

 

posted @ 2016-05-29 23:44  CtrlCV  阅读(750)  评论(0编辑  收藏  举报