后缀排序【后缀数组入门题】

后缀数组真的是好难理解阿,我觉得我一辈子都看不懂了。只能靠模板过日子。

这是一篇我觉得很好的博客:https://www.cnblogs.com/zwfymqz/p/8413523.html#_labelTop

题目链接:https://www.luogu.org/problemnew/show/P3809

题目大意:读入一个长度为 n 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 1 到 n。

思路:模板题,sa[i]数组的含义为排名为i的后缀第一个字符在原字符串中的位置。所以跑一边模板求得sa数组即可。

代码如下:

各个数组的含义都写在代码中了

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 const int MAXN = 1e6 + 10;
 6 
 7 char s[MAXN]; //读入字符串 
 8 int N, M, cnt;//N为字符串的长度 len,M为字符串中字符的字符集大小size .
 9 //例如小写字母是26个,大写字母26个,小写+大写就翻倍。暴力点直接用ascii码上限做字符集大小也可以 
10 //cnt是有多少个不同的后缀排序 
11 int rank[MAXN];//以i下标为首的后缀的排名
12 int sa[MAXN];//排名为i的后缀首字符所在下标 
13 int tax[MAXN];//i号元素出现了多少次。辅助基数排序 
14 int tp[MAXN];//基数排序的第二关键字,意义与sa一样,即第二关键字排名为i的后缀首字符所在下标 
15 
16 void Qsort()
17 {
18     for(int i = 0; i <= M; i ++)    tax[i] = 0;
19     for(int i = 1; i <= N; i ++)    tax[rank[i]] ++;
20     for(int i = 1; i <= M; i ++)    tax[i] += tax[i - 1];
21     for(int i = N; i >= 1; i --)    sa[tax[rank[tp[i]]] --] = tp[i];
22 }
23 
24 void get_SA()
25 {
26     for(int i = 1; i <= N; i ++)    rank[i] = s[i] - '0' + 1, tp[i] = i;
27     Qsort();
28     for(int w = 1; w <= N; w *= 2)
29     {
30         cnt = 0;
31         for(int i = 1; i <= w; i ++)    tp[++ cnt] = N - w + i;
32         for(int i = 1; i <= N; i ++)    if(sa[i] > w)    tp[++ cnt] = sa[i] - w;
33         Qsort();
34         swap(tp, rank);
35         rank[sa[1]] = cnt = 1;
36         for(int i = 2; i <= N; i ++)
37             rank[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w]  == tp[sa[i] + w]) ? cnt : ++ cnt;
38         M = cnt;
39         if(cnt == N)
40             break;
41     }
42     for(int i = 1; i <= N; i ++)
43         printf("%d ", sa[i]);
44 }
45 
46 int main()
47 {
48     scanf("%s", s + 1);
49     N = strlen(s + 1);
50     M = 75;
51     get_SA();
52     return 0;
53 }
后缀数组求sa模板

 

posted @ 2019-07-19 18:31  缘未到  阅读(267)  评论(0编辑  收藏  举报