tyvj1860后缀数组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }

 

以上是关于tyvj1860后缀数组的主要内容,如果未能解决你的问题,请参考以下文章

tyvj1860后缀数组

tyvj P1519 博彩游戏(AC自动机+DP滚动数组)

[P1860新魔法药水]

[Tyvj1001]第K极值 (贪心?模拟)

[TyvjP1515] 子串统计 [luoguP2408] 不同子串个数(后缀数组)

TYVJ1305 最大子序和