【tyvj1860】后缀数组

描述

我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串。
后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较
定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0
你的任务就是求出SA和height这两个数组。字符串长度<=200000

输入格式

一行,为描述中的字符串(仅会出现小写字母)

输出格式

共两行,每行n个数,第一行为sa[i],第二行为height[i],其中每行的数均用空格隔开

测试样例1

输入

aabaaaab

输出

4 5 6 1 7 2 8 3 
0 3 2 3 1 2 0 1

题目告诉我们这是一个模板题,这的确就是一个模板题,geth函数还不是太理解。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<set>
 6 #include<ctime>
 7 #include<vector>
 8 #include<cmath>
 9 #include<algorithm>
10 #include<map>
11 #define inf 2000000000
12 #define N 200005
13 int n;
14 char ch[N];
15 int a[N],h[N];
16 int v[N];
17 int sa[2][N],rk[2][N];
18 int p,q,k;
19 void init(){
20     scanf("%s",ch+1);
21     n=strlen(ch+1);
22     for (int i=1;i<=n;i++) a[i]=ch[i]-‘a‘+1;
23 }
24
25 void change(int sa[N],int rk[N],int SA[N],int RK[N]){
26     for (int i=1;i<=n;i++) v[rk[sa[i]]]=i;//该排名最后出现的位置
27     for (int i=n;i>=1;i--) if (sa[i]>k)
28         SA[v[rk[sa[i]-k]]--]=sa[i]-k;//?
29     for (int i=n-k+1;i<=n;i++) SA[v[rk[i]]--]=i;//?
30     for (int i=1;i<=n;i++)  RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i-1]]!=rk[SA[i]]||rk[SA[i-1]+k]!=rk[SA[i]+k]);
31
32 }
33
34 void work(){
35      q=1,p=0;
36     for (int i=1;i<=n;i++) v[a[i]]++;
37     for (int i=1;i<=26;i++)v[i]+=v[i-1];
38     for (int i=1;i<=n;i++) sa[p][v[a[i]]--]=i;
39     for (int i=1;i<=n;i++) rk[p][sa[p][i]]=(rk[p][sa[p][i-1]])+(a[sa[p][i-1]]!=a[sa[p][i]]);
40     k=1;
41     while (k<n){
42         change(sa[p],rk[p],sa[q],rk[q]);
43         p^=1;q^=1;k=k<<1;
44     }
45     for (int i=1;i<=n;i++) printf("%d ",sa[p][i]);
46 }
47
48 void geth(){
49     int k=0;
50     for (int i=1;i<=n;i++)
51     if (rk[p][i]==1)h[rk[p][i]]=0;
52     else{
53         int j=sa[p][rk[p][i]-1];
54         while (a[i+k]==a[j+k])k++;
55         h[rk[p][i]]=k;if (k>0)k--;
56     }
57 }
58
59 int main(){
60     init();
61     work();
62     geth();
63     puts("");
64     for(int i=1;i<=n;i++)printf("%d ",h[i]);
65 }
时间: 2024-08-04 18:34:21

【tyvj1860】后缀数组的相关文章

[tyvj1860]后缀数组

P1860 后缀数组 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串. 后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较 定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0 你的任务就

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

hdu5769--Substring(后缀数组)

题意:求含有某个字母的某个字符串的不同子串的个数 题解:后缀数组,记录每个位置距离需要出现的字母的距离就可以了.因为不太了解后缀模版卡了一会,还是很简单的. 记住sa和height数组都是1-n的下标. //后缀数组 #include <stdio.h> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll;

hdu 3518 Boring counting 后缀数组LCP

题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output 2 3 3 思路:套用后缀数组求解出sa数组和height数组,之后枚举后缀的公共前缀长度i,由于不能重叠,所以计数的是相邻height不满足LCP >= i的. 写写对后缀数组倍增算法的理解: 1.如果要sa数组对应的值也是1~n就需要在最后加上一个最小的且不出现的字符'#',里面y[]是利用sa数

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

hdu 4416 Good Article Good sentence(后缀数组&amp;思维)

Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2308    Accepted Submission(s): 649 Problem Description In middle school, teachers used to encourage us to pick up pre

uva 10829 - L-Gap Substrings(后缀数组)

题目链接:uva 10829 - L-Gap Substrings 题目大意:给定一个字符串,问有多少字符串满足UVU的形式,要求U非空,V的长度为g. 解题思路:对字符串的正序和逆序构建后缀数组,然后枚举U的长度l,每次以长度l分区间,在l和l+d+g所在的两个区间上确定U的最大长度. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using nam

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>