CodeVS1500 后缀排序
题目描述 Description
天凯是MIT的新生。Prof. HandsomeG给了他一个长度为n的由小写字母构成的字符串,要求他把该字符串的n个后缀(suffix)从小到大排序。
何谓后缀?假设字符串是S=S1S2……Sn,定义Ti=SiSi+1……Sn。T1, T2, …, Tn就叫做S的n个后缀。
关于字符串大小的比较定义如下(比较规则和PASCAL中的定义完全相同,熟悉PASCAL的同学可以跳过此段):
若A是B的前缀,则A<B;否则令p满足:A1A2…Ap-1=B1B2…Bp-1,Ap<>Bp。如果Ap<Bp,则A<B;否则A>B。
输入描述 Input Description
第一行一个整数n(n<=15000)
第二行是一个长度为n字串。
输出描述 Output Description
输出文件包含n行,第i行是一个整数pi。表示所有的后缀从小到大排序后是Tp1, Tp2, …, Tpn。
样例输入 Sample Input
4
abab
样例输出 Sample Output
3
1
4
2
数据范围及提示 Data Size & Hint
说明:后缀排序后的顺序是T3=”ab”, T1=”abab”, T4=”b”, T2=”bab”。所以输出是3, 1, 4, 2。
代码
//CodeVS1500 后缀排序 后缀数组
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 16000
using namespace std;
char str[maxn];
int sa[maxn], wa[maxn], wb[maxn], wv[maxn], ws[maxn], n, s[maxn];
bool cmp(int *r, int a, int b, int l)
{return r[a]==r[b] and r[a+l]==r[b+l];}
void da(int *r, int *sa, int n, int m)
{
int i, j, p, *x=wa, *y=wb, *t;
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[x[i]=r[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
for(j=p=1;p<n;j<<=1,m=p)
{
for(p=0,i=n-j;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0;i<n;i++)wv[i]=x[y[i]];
for(i=0;i<m;i++)ws[i]=0;
for(i=0;i<n;i++)ws[wv[i]]++;
for(i=1;i<m;i++)ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
int main()
{
int i;
scanf("%d%s",&n,str);
for(i=0;i<n;i++)s[i]=str[i];
da(s,sa,n+1,300);
for(i=1;i<=n;i++)printf("%d\n",sa[i]+1);
return 0;
}