这是一道模板题。
读入一个长度为
n
的由小写英文字母组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为
除此之外为了进一步证明你确实有给后缀排序的超能力,请另外输出
直接上模板了……机房要关门了……我要吃饭了……
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 100000 + 5;
int sa[MAXN],rank[MAXN],tmp[MAXN];
int n,k;
char c[MAXN];
bool cmp_sa(int a,int b)
{
if(rank[a] != rank[b])
return rank[a] < rank[b];
else
{
int x = a + k <= n ? rank[a + k] : -1;
int y = b + k <= n ? rank[b + k] : -1;
return x < y;
}
}
void make_sa(char s[])
{
for(int i = 0;i <= n;i ++)
{
rank[i] = i < n ? s[i] : -1;
sa[i] = i;
}
for(k = 1;k <= n;k <<= 1)
{
sort(sa,sa + n + 1,cmp_sa);
tmp[sa[0]] = 0;
for(int i = 1;i <= n;i ++)
tmp[sa[i]] = tmp[sa[i - 1]] + cmp_sa(sa[i - 1],sa[i]);
for(int i = 0;i <= n;i ++)
rank[i] = tmp[i];
}
return;
}
int lcp[MAXN];
void make_lcp(char s[])
{
for(int i = 1;i < n;i ++)
rank[sa[i]] = i;
int h = 0;
lcp[0] = 0;
for(int i = 0;i < n;i ++)
{
int j = sa[rank[i] - 1];
if(h)
h--;
for(;i + h < n && j + h < n;h ++)
if(s[i + h] != s[j + h])
break;
lcp[rank[i] - 1] = h;
}
return;
}
int main()
{
scanf("%s",c);
n = strlen(c);
make_sa(c);
for(int i = 1;i <= n;i ++)
printf("%d ",sa[i] + 1);
puts("");
make_lcp(c);
for(int i = 1;i < n;i ++)
printf("%d ",lcp[i]);
return 0;
}
//2016.4.7才发现这个是CE的代码……