【后缀数组】洛谷P3809模板题
题目背景
这是一道模板题。
题目描述
读入一个长度为 n n n 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 1 1 1 到 n n n。
输入输出格式
输入格式:一行一个长度为 n n n 的仅包含大小写英文字母或数字的字符串。
输出格式:一行,共n个整数,表示答案。
输入输出样例
说明
n<=106n <= 10^6n<=106
题解
倍增算法的后缀数组
表示并不会DC3
代码
//by 减维 #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<bitset> #include<set> #include<cmath> #include<vector> #include<set> #include<map> #include<ctime> #include<algorithm> #define ll long long #define db double #define inf 1<<30 #define maxn 1000005 #define eps 1e-8 using namespace std; int n,m,a[maxn],c[maxn],sa[maxn],tp[maxn],rnk[maxn],hei[maxn]; char s[maxn]; void srt() { for(int i=0;i<=m;++i)c[i]=0; for(int i=1;i<=n;++i)c[rnk[tp[i]]]++; for(int i=1;i<=m;++i)c[i]+=c[i-1]; for(int i=n;i;i--)sa[c[rnk[tp[i]]]--]=tp[i]; } bool cmp(int *f,int x,int y,int w){return f[x]==f[y]&&f[x+w]==f[y+w];} void getsa() { for(int i=1;i<=n;++i)rnk[i]=a[i],tp[i]=i; m=303;srt(); for(int p=1,ln=1;p<n;ln+=ln,m=p) { p=0; for(int i=n-ln+1;i<=n;++i)tp[++p]=i; for(int i=1;i<=n;++i)if(sa[i]>ln)tp[++p]=sa[i]-ln; srt();swap(tp,rnk);rnk[sa[1]]=p=1; for(int i=2;i<=n;++i)rnk[sa[i]]=cmp(tp,sa[i],sa[i-1],ln)?p:++p; } int k=0,j; for(int i=1;i<=n;hei[rnk[i++]]=k) for(k=k?k-1:k,j=sa[rnk[i]-1];a[j+k]==a[i+k];k++); } int main() { scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;++i)a[i]=s[i]; getsa(); for(int i=1;i<=n;++i)printf("%d ",sa[i]); return 0; }