题目:https://www.luogu.org/problemnew/show/P3809
刚学了后缀数组,看人家手写演示了半天,大概明白了过程,但完全写不出来代码;
于是借鉴了许多,不过都差不多,总算会写了;
如何把想法实现出来很重要啊...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=1e6+5; int n,m,rk[maxn],tp[maxn],sa[maxn],a[maxn],num,tax[maxn]; char s[maxn]; void Rsort() { for(int i=0;i<=m;i++)tax[i]=0; for(int i=1;i<=n;i++)tax[rk[tp[i]]]++; for(int i=1;i<=m;i++)tax[i]+=tax[i-1]; for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];//tp是位置,rk是该位置第一关键字排名,tax存数量 //tp[i]是第二关键字从小到大进入,所以从大到小出来就可以使用前缀 } void work() { for(int i=1;i<=n;i++)rk[i]=a[i],tp[i]=i; Rsort(); for(int k=1;k<=n;k<<=1) { num=0; for(int i=n-k+1;i<=n;i++)tp[++num]=i;//n-k以后的i后缀第二关键字是0,字典序最小 for(int i=1;i<=n;i++)//枚举排名(上一次的,也就是本次第一关键字) if(sa[i]>k)tp[++num]=sa[i]-k;//排名从小到大,其所在位置如果大于k,则可以作为本次第二关键字 //sa[i]-k 是位置,若上一次的第i名作为本次第二关键字,则所得后缀的位置在sa[i]-k Rsort(); swap(rk,tp);//tp存下上一次排名,也就是本次第一关键字的排名 rk[sa[1]]=1; num=1; for(int i=2;i<=n;i++) rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num; //比较前后两半排名是否相同 if(num==n)break; m=num;//m是种类 } } int main() { cin>>s; n=strlen(s); m=122; for(int i=1;i<=n;i++)a[i]=s[i-1]; work(); for(int i=1;i<=n;i++)printf("%d ",sa[i]); return 0; }