先粘上我入门时看的博客:
https://www.cnblogs.com/jinkun113/p/4743694.html
https://www.cnblogs.com/victorique/p/8480093.html
https://www.cnblogs.com/jinkun113/p/4743694.html
声明:以下部分内容摘自该博客,仅供个人复习时用
后缀数组是让人蒙逼的有力工具! 后缀数组是处理字符串的有力工具,可以解决很多关于字符串的问题
注意:后缀数组并不是一种算法,而是一种思想。
实现它的方法主要有两种:倍增法O(nlogn) 和 DC3法O(n)
其中倍增法除了仅仅在时间复杂度上不占优势之外,其他的方面例如编程难度,空间复杂度,常数等都秒杀DC3法
建议深入理解倍增法,并能熟练运用(起码8分钟内写出来&&没有错误)。DC3法只做了解。
https://www.luogu.org/problem/P3809
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <stack> 9 #include <queue> 10 #include <set> 11 #include <map> 12 #include <math.h> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 const int mod=1e9+7; 16 const int maxn=1e6+10; 17 using namespace std; 18 19 char str[maxn]; 20 int sa[maxn];//排名为i的后缀的位置 21 int rk[maxn];//从第i个位置开始的后缀的排名 22 int C[maxn];//C数组表示桶,统计每种元素出现了多少次,辅助基数排序 23 int X[maxn];//X[i]是第i个元素的第一关键字的字典排名 24 int Y[maxn];//Y[i]表示在第二关键字中排名为i的数,其第一关键字的位置 25 26 int n,m; 27 void Get_SA() 28 { 29 for(int i=1;i<=n;i++) 30 C[X[i]=str[i]]++; 31 for(int i=2;i<=m;i++)//做C的前缀和,我们就可以得出每个关键字最多是在第几名 32 C[i]+=C[i-1]; 33 for(int i=n;i>=1;i--) 34 sa[C[X[i]]--] = i; 35 36 for(int k = 1; k <= n; k <<= 1) 37 {//k:当前倍增的长度,k = x表示已经求出了长度为x的后缀的排名,现在要更新长度为2x的后缀的排名 38 int num=0; //num仅仅是一个计数器,示不同的后缀的个数,很显然原字符串的后缀都是不同的,因此num=n时可以退出循环 39 40 for(int i=n-k+1;i<=n;i++)//第n-k+1到第n位是没有第二关键字的 所以排名在最前面 41 Y[++num]=i; 42 for(int i=1;i<=n;i++) 43 if(sa[i]>k) 44 Y[++num]=sa[i]-k; 45 //排名为i的数 在数组中是否在第k位以后,即满足(sa[i]>k),那么它可以作为别人的第二关键字,就把它的第一关键字的位置添加进Y就行了 46 //所以i枚举的是第二关键字的排名,第二关键字靠前的先入队 47 48 for(int i=1;i<=m;i++) 49 C[i]=0;//初始化C桶 50 for(int i=1;i<=n;i++) 51 C[X[Y[i]]]++; 52 //因为上一次循环已经算出了这次的第一关键字 所以直接加就行了 53 for(int i=1;i<=m;i++) 54 C[i]+=C[i-1];//第一关键字排名为1~i的数有多少个 55 for(int i=n;i>=1;i--) 56 sa[C[X[Y[i]]]--]=Y[i]; 57 //因为Y的顺序是按照第二关键字的顺序来排的,第二关键字靠后的,在同一个第一关键字桶中排名越靠后 58 59 swap(X,Y);//这里不用想太多,因为要生成新的X时要用到旧的,就把旧的复制下来,没别的意思 60 num=1; 61 X[sa[1]]=1; 62 for(int i=2;i<=n;i++)//因为sa[i]已经排好序了,所以可以按排名枚举,生成下一次的第一关键字X; 63 X[sa[i]]=(Y[sa[i]]==Y[sa[i-1]] && Y[sa[i]+k]==Y[sa[i-1]+k]) ? num : ++num; 64 if(num==n) 65 break; 66 m=num;//这里就不用那个122了,因为都有新的编号了 67 } 68 } 69 70 int main() 71 { 72 gets(1+str); 73 n=strlen(1+str); 74 m=122; 75 Get_SA(); 76 for(int i=1;i<=n;i++) 77 { 78 if(i==1) 79 printf("%d",sa[i]); 80 else 81 printf(" %d",sa[i]); 82 } 83 printf("\n"); 84 return 0; 85 }
两个后缀的最大公共前缀
lcp(x,y)=min(heigh[x−y]), 用rmq维护,O(1)查询
可重叠最长重复子串
Height数组里的最大值
不可重叠最长重复子串 POJ1743
首先二分答案x,对height数组进行分组,保证每一组的minheight都>=x>=x
依次枚举每一组,记录下最大和最小长度,多sa[mx]−sa[mi]>=x那么可以更新答案
本质不同的子串的数量
枚举每一个后缀,第i个后缀对答案的贡献为len−sa[i]+1−height[i]
声明:我博客里有大量的从别的博客复制过来的代码,分析,以及理解,但我一律会在文章后面标记原博客大佬博客地址,其中部分会加以连接。 绝无抄袭的意思,只是为了我在复习的时候找博客方便。 如有原作者对此有不满,请在博客留言,我一定会删除该博文。
原文:https://www.cnblogs.com/jiamian/p/11503808.html