版权声明: https://blog.csdn.net/qq_16267919/article/details/82108744
建议参考:后缀数组——处理字符串的有力工具
后缀排序即对一个字符串的每一个后缀进行排序,如果暴力进行排序,考虑到字符串比较的复杂度,效率至少是
级别的.
考虑依次对每个位置开始的
个字符进行分组,把他们看成一个字符串,从小到大枚举
进行处理,
的排名即
的排名,使用基数排序即可做到
的复杂度.
表示第
大的后缀的位置
bool cmp(LL *x,LL a,LL b,LL l)
{
return x[a]==x[b] && x[a+l]==x[b+l];
}
void px()
{
LL i,j,p,*x=X,*y=Y;
fo(i,0,n-1) buc[x[i]=s[i]]++;
fo(i,1,M) buc[i]+=buc[i-1];
fd(i,n-1,0) sa[--buc[s[i]]]=i;//从大到小枚举
for(j=1,p=0;p<n;j<<=1)
{
p=0;//别忘了
fo(i,n-j,n-1) y[p++]=i;
fo(i,0,n-1) if (sa[i]>=j) y[p++]=sa[i]-j;
fo(i,0,n-1) _rk[i]=x[y[i]];
qk(buc);
fo(i,0,n-1) buc[_rk[i]]++;
fo(i,1,M) buc[i]+=buc[i-1];
fd(i,n-1,0) sa[--buc[_rk[i]]]=y[i];//从大到小枚举
swap(x,y); p=1; x[sa[0]]=0; y[n]=-1;//别忘了
fo(i,1,n-1)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
设 表示第 大的后缀和第 大的后缀的最长公共前缀,那么有 ,可以这样求
fo(i,0,n-1) rk[sa[i]]=i;
LL j=0;
fo(i,0,n-1)
{
if (!rk[i]) continue;
j=j?j-1:j;
fo(j,j,n-1)
if (s[i+j]!=s[sa[rk[i]-1]+j]) break;
h[rk[i]]=j;
}
SPOJ_NSUBSTR
题意:求长度为
到
的重复次数最多子串的重复次数(可以相交)
先后缀排序求出
数组,用单调栈左右各扫一遍求出每个位置
是哪一段极长区间的最小值,区间长度就是
的值