后缀数组总结
Posted fexuile
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了后缀数组总结相关的知识,希望对你有一定的参考价值。
感觉SA还是有点用处的所以还是用用的好。
定义
首先是一些定义,这是后缀数组的基础。
\(sa_i\)表示按照字典序从小到大排序后第\(i\)个串是\(sa_i\)这个后缀。
\(rank_i\)表示\(i\)这个后缀对应的是第几个(排名)。
\(height_i\)表示的是\(lcp(sa_i,sa_i-1)\)的长度。
代码其实很容易,就是一个基数排序+倍增,也很容易理解(
主要是应用方面还是要多做一些题目的好。
代码实现
/*
mail: mleautomaton@foxmail.com
author: MLEAutoMaton
This Code is made by MLEAutoMaton
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi()
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0')if(ch=='-')f=-1;ch=getchar();
while(ch>='0' && ch<='9')sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();
return f*sum;
const int N=4000010,Mx=510;
int t[N],n,k,x[N],sa[N],height[N],rnk[N],y[N];
char a[N];
bool cmp(int a,int b,int lim)
return (y[a]==y[b] && y[a+lim]==y[b+lim]);
void get_sa()
int m=150;
for(int i=1;i<=m;i++)t[i]=0;
for(int i=1;i<=n;i++)t[x[i]=a[i]]++;
for(int i=1;i<=m;i++)t[i]+=t[i-1];
for(int i=n;i;i--)sa[t[x[i]]--]=i;
int p=0;
for(int lim=1;p<=n && lim<=n;lim<<=1)
p=0;
for(int i=n-lim+1;i<=n;i++)y[++p]=i;
for(int i=1;i<=n;i++)if(sa[i]>lim)y[++p]=sa[i]-lim;
for(int i=1;i<=m;i++)t[i]=0;
for(int i=1;i<=n;i++)t[x[y[i]]]++;
for(int i=1;i<=m;i++)t[i]+=t[i-1];
for(int i=n;i;i--)sa[t[x[y[i]]]--]=y[i];
swap(x,y);x[sa[1]]=1;p=2;
for(int i=2;i<=n;i++)x[sa[i]]=cmp(sa[i],sa[i-1],lim)?p-1:p++;
m=p;
for(int i=1;i<=n;i++)rnk[sa[i]]=i;
for(int i=1,j=0;i<=n;i++)
j=max(0,j-1);int lst=sa[rnk[i]-1];
while(a[i+j]==a[lst+j])j++;
height[rnk[i]]=j;
// for(int i=1;i<=n;i++)printf("%d %d\n",sa[i],height[i]);
bool check(int mid)
int sum=1;
for(int i=1;i<=n;i++)
if(height[i]>=mid)
sum++;
if(sum>=k)return true;
else sum=1;
return false;
int main()
// n=gi();k=gi();
// for(int i=1;i<=n;i++)a[i]=gi();
scanf("%s",a+1);n=strlen(a+1);
get_sa();
/* int l=0,r=n,ans=0;
while(l<=r)
int mid=(l+r)>>1;
if(check(mid))l=mid+1;ans=mid;
else r=mid-1;
*/
// printf("%d\n",ans);
for(int i=1;i<=n;i++)printf("%d%c",sa[i],i==n?'\n':' ');
return 0;
以上是关于后缀数组总结的主要内容,如果未能解决你的问题,请参考以下文章