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