首页 > 编程语言 > 详细

后缀数组总结

时间:2019-10-05 22:57:43      阅读:129      评论:0      收藏:0      [点我收藏+]

感觉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;
}

后缀数组总结

原文:https://www.cnblogs.com/fexuile/p/11625851.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!