UOJ35 后缀数组(模板)

#35. 后缀排序

这是一道模板题。

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

除此之外为了进一步证明你确实有给后缀排序的超能力,请另外输出 n−1n−1 个整数分别表示排序后相邻后缀的最长公共前缀的长度。

输入格式

一行一个长度为 nn 的仅包含小写英文字母的字符串。

输出格式

第一行 nn 个整数,第 ii 个整数表示排名为 ii 的后缀的第一个字符在原串中的位置。

第二行 n−1n−1 个整数,第 ii 个整数表示排名为 ii 和排名为 i+1i+1 的后缀的最长公共前缀的长度。

样例一

input

ababa

output

5 3 1 4 2
1 3 0 2

explanation

排序后结果为:

  1. a
  2. aba
  3. ababa
  4. ba
  5. baba

正解:后缀数组

解题报告:
  模板,第一次交才发现我原来的模板是个萎的,太恐怖了。。。

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 const int MAXN = 300011;
21 char ch[MAXN];
22 int n,m,tot;
23 int wa[MAXN],wb[MAXN],wv[MAXN],c[MAXN];
24 int rank[MAXN],height[MAXN];
25 int sa[MAXN];
26
27 inline int getint()
28 {
29        int w=0,q=0;
30        char c=getchar();
31        while((c<‘0‘ || c>‘9‘) && c!=‘-‘) c=getchar();
32        if (c==‘-‘)  q=1, c=getchar();
33        while (c>=‘0‘ && c<=‘9‘) w=w*10+c-‘0‘, c=getchar();
34        return q ? -w : w;
35 }
36
37 inline void da(int m){
38     int i,*x=wa,*y=wb;
39     for(i=1;i<=m;i++) c[i]=0;
40     for(i=1;i<=n;i++) c[x[i]=(ch[i]-‘a‘+1)]++;
41     for(i=1;i<=m;i++) c[i]+=c[i-1];
42     for(i=n;i>=1;i--) sa[c[x[i]]--]=i;
43     for(int k=1,p;k<=n;k=k*2) {
44     p=0;
45     for(i=n-k+1;i<=n;i++) y[++p]=i;
46     for(i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
47     for(i=1;i<=m;i++) c[i]=0;
48     for(i=1;i<=n;i++) c[x[y[i]]]++;
49     for(i=1;i<=m;i++) c[i]+=c[i-1];
50     for(i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i];
51     swap(x,y);  x[sa[1]]=1; p=1;
52     for(i=2;i<=n;i++) x[sa[i]]=(y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?p:++p;
53     if(p==n) break; m=p;
54     }
55 }
56
57 inline void calheight(){
58     int i,j,k=0;
59     for(i=1;i<=n;height[rank[i++]]=k)
60     for(k?k--:0 , j=sa[rank[i]-1];ch[i+k]==ch[j+k];k++) ;
61 }
62
63 inline void work(){
64     scanf("%s",ch+1);   n=strlen(ch+1);
65     da(256);
66     for(int i=1;i<=n;i++) rank[sa[i]]=i;
67     calheight();
68     for(int i=1;i<=n;i++) printf("%d ",sa[i]);
69     printf("\n");
70     for(int i=2;i<=n;i++) printf("%d ",height[i]);
71 }
72
73 int main()
74 {
75   work();
76   return 0;
77 }
时间: 2024-10-05 06:15:37

UOJ35 后缀数组(模板)的相关文章

后缀数组模板第一版

/*---------------倍增算法+RMQ后缀数组模板-------------- 输入:从0开始的字符串g,长度len最大为10^6 输出: sa[]表示:n 个后缀从小到大进行排序之后把排好序的后缀的开头位置顺 次放入 sa 中,sa[i]表示排第i位的字符串开头是sa[i],因为添加了一个结尾0,所以sa[0]=len height 数组(h[]):定义 h[i]=suffix(sa[i-1])和 suffix(sa[i])的最长公 共前缀,也就是排名相邻的两个后缀的最长公共前缀.

后缀数组模板一份

1 /****************** 2     by zhuyuqi      * 3     QQ:1113865149 * 4     name:2-sat    * 5                   * 6 ******************/ 7  8 using namespace std; 9 const int MAX = 1000;10 int r[MAX],*rank;11 int wa[MAX],wb[MAX],ws[MAX],wv[MAX];12 int h

后缀数组模板/LCP模板

1 //后缀数组模板,MANX为数组的大小 2 //支持的操作有计算后缀数组(sa数组), 计算相邻两元素的最长公共前缀(height数组),使用get_height(); 3 //计算两个后缀a, 和b的最长公共前缀,请先使用lcp_init(),再调用get_lcp(a, b)得到 4 //下面的n是输入字符串的长度+1(n = strlen(s) + 1), m是模板的范围 m=128表示在字母,数字范围内,可以扩大也可缩小 5 //s[len] 是插入的一个比输入字符都要小的字符 6 s

后缀数组模板及解释

以前做过后缀数组,直接用模板,最近打算重新认真的学一遍.感觉学一个东西一定要弄懂了,不然到最后还是要重学. int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN]; void da(int *r,int *sa,int n,int m){//n表示字符串长度 + 1,包括添加的那个0,m表示取值的范围 //把单个字符进行基数排序 int *x = wa,*y = wb; for(int i = 0; i < m; i++)Ws[i] = 0; for(int i = 0;

后缀数组模板及一些数组的含义

最近学习了一下后缀数组,模板原理以后再看,先记一下一些数组的含义.用以下这张图做例子: rank(i)代表第i个后缀的字典序排名 sa(i)代表排名为i的字典序对应的位置 lcp(i, j)表示suffix(i)和suffix(j)的公共最长前缀 height(i) = lcp(sa(i-1), sa(i)) 当rank(i)<rank(j),有lcp(i,j) = min(height(k)),   rank(i)<k<=rank(j) 原文地址:https://www.cnblogs

hdu1403(后缀数组模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 题意: 给出两个字符串, 求他们的最长公共子串 思路: 两个字符串的最长公共子串长度显然就是两个字符串的所有后缀中的最长公共前缀长度. 可以先用一个没有出现的字符(便于后面区分后缀是否属于相同字符串)将两个字符串连成一个字符串,再用后缀数组求其height, SA数组, 对于当前 i, 通过 SA 数组区分后缀 i 和 i - 1 是否在同一个初始字符串中, 若不是则用 height[i] 维

后缀数组 模板题 hdu1403(最长公共(连续)子串)

好气啊,今天没有看懂后缀树和后缀自动机 只能写个后缀数组发泄一下了orz #include <cstdio> #include <cstring> const int N = 100017*2; int wa[N], wb[N], wv[N], ws[N]; int rank[N]; int height[N]; char str[N]; int s[N], sa[N]; int cmp(int *r, int a, int b, int l) { return r[a]==r[b

后缀数组模板 SuffixArray

1 #include<bits/stdc++.h> 2 #define rep(i,a,b) for(i=a;i<b;++i) 3 #define drep(i,a,b) for(i=b;i>=a;--i) 4 using namespace std; 5 int p[N],wc[N],wv[N],wa[N],wb[N],rank[N],sa[N]; 6 char s[N]; 7 inline bool cmp(int *r,int a,int b,int l) { 8 retur

后缀数组模板(理解)

字符串的处理真可谓是博大精深,后缀数组这种数据结构我花了两天时间才明白了其构造的过程.主要是代码不好理解. 数据结构: 1.sa数组,就是后缀数组,按照字典序排列,其意义为:sa[i]=k,排第i名的子串是从k位开始的. 2.rank名次数组,其意义为:rank[i]=k,以i为起点的子串排名为k. 很容易看出来两者可以相互转化. 求这两个数组的过程是基于基数排序,计数排序的方法. 下面是一个大牛的注释版.其中我在补充点: 1.对于求y[]这个数组,因为已经知道上次长为j的子串比较结果,那么这次