#后缀数组 ### 倍增算法   主要思想就是先对单个字符排序,再根据单个字符排序的结果通过移位得到下一个单个字符的排序结果,再排序就可以得到两个字符组成的子串的排序结果;再移位和合并排序得到四个字符组成的子串的排序结果…因此要确定次序的子串长度是按指数增长的,加之使用基数排序每次的复杂度为$O(n)$,总的时间复杂度为$O(nlogn)$. ```c++ int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i=0;i--) sa[--ws[x[i]]]=i; for(j=1,p=1;p=j) y[p++]=sa[i]-j; for(i=0;i=0;i--) sa[--ws[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i=0;i--) b[--ws[wv[i]]]=a[i]; return; } void dc3(int *r,int *sa,int n,int m) { int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p; r[n]=r[n+1]=0; for(i=0;ih[i-1]-1$   证明:假设$i$和$j$满足$rank[i]-rank[j]=1$,那么这两个后缀的最长公共前缀长度即为$h[i]$,现在考虑原字符串中起始位置在$j$之后和$i$之后的两个后缀,这里记为$j+1$和$i+1$   第一种情况:第$i$和$j$两个后缀的首字符不一样,那么$h[i]=0$,总有$h[i+1]\ge h[i]-1$   第二种情况:第$i$和$j$两个后缀的首字符一样,那么第$i+1$和第$j+1$这两个后缀分别是由第$i$和第$j$个后缀去掉首字符得到的,显然第$j+1$个字符排在第$i+1$个后缀之前,它们的最长公共前缀长度为$h[i]-1$;再考虑比第$i+1$个后缀排序更靠前的后缀中,一定是与它相邻的后缀和它有最长的公共前缀(*可以理解为相似度更高*),也就是说名次为$rank[i+1]$(*这里的$i+1$是指在字符串里的位置*)的后缀和名次为$rank[i+1]-1$的后缀的最长公共前缀至少是$h[i]-1$(*因为第$j+1$个后缀至少也要在第$i+1$个后缀的前面一位*),即$h[i+1]\ge h[i]-1$(*这里$i$和$i+1$就是指在字符串里的位置*)   这里举个栗子,对于字符串$aabaaaab$,它的$rank$数组为[4,6,8,1,2,3,5,7],我们假设$i=6,j=5$;那么$suffix(i)=abaaaab,suffix(j)=ab$,而第$i+1$个后缀为$baaaab$,第$j+1$个后缀为$b$,第$j+1$个后缀一定在$i+1$个后缀的前面,而且第$i+1$个后缀的$rank$值为8,第$j+1$个后缀的$rank$值为7,我们说$height[rank[7]]\ge height[rank[6]]-1$,这里因为第$j+1$个后缀的排名恰为第$i+1$个后缀的排名的前一个,所以取等号 #### 代码实现 ```c++ int rank[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=1;i<=n;i++) rank[sa[i]]=i; for(i=0;i