题目背景
这是一道模板题。
题目描述
读入一个长度为 nn 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 11 到 nn 。
输入输出格式
输入格式:
一行一个长度为 nn 的仅包含大小写英文字母或数字的字符串。
输出格式:
一行,共n个整数,表示答案。
输入输出样例
输入样例#1: 复制
ababa
输出样例#1: 复制
5 3 1 4 2
说明
n <= 10^6n<=106
题解:
后缀数组模板题。
后缀数组的思想很简单,但具体方面实在是有些难以理解,但也不至于有后缀自动机那么难,我看了一个晚上才看明白。
不复习估计很快就忘了,要经常复习才行(我现在就有点迷了)。
代码:
#include<bits/stdc++.h>
using namespace std;
int M,n,m,tax[1000001],rak[1000001],sa[1000001],tp[1000001];
char s[1000001];
void px(){
int i;
for(i=0;i<=M;i++)tax[i]=0;
for(i=1;i<=n;i++)tax[rak[i]]++;
for(i=1;i<=M;i++)tax[i]+=tax[i-1];
for(i=n;i;i--)sa[tax[rak[tp[i]]]--]=tp[i];
}
void getsuffix(){
int i,m,p;
M=100;
for(i=1;i<=n;i++)rak[i]=s[i]-'0',tp[i]=i;
px();
for(m=1,p=0;p<n;M=p,m*=2){
p=0;
for(i=1;i<=m;i++)tp[++p]=n-m+i;
for(i=1;i<=n;i++)
if(sa[i]>m)tp[++p]=sa[i]-m;
px();
swap(tp,rak);
rak[sa[1]]=p=1;
for(i=2;i<=n;i++)
rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+m]==tp[sa[i]+m])?p:++p;
}
}
int main(){
int i;
scanf("%s",s+1);
n=strlen(s+1);
getsuffix();
for(i=1;i<=n;i++)printf("%d ",sa[i]);
}