题目链接
The B-function B ( t 1 t 2 … t k ) = b 1 b 2 … b k B(t_1 t_2 \dots t_k) = b_1 b_2 \dots b_k B(t1t2…tk)=b1b2…bk of a string t 1 t 2 … t k t_1 t_2 \dots t_k t1t2…tk is defined as follows.
Given a string s 1 s 2 … s n s_1 s_2 \dots s_n s1s2…sn, sort its n n n suffixes into increasing lexicographically order of the B-function.
Formally, the task is to find a permutaion p 1 , p 2 , … , p n p_1, p_2, \dots, p_n p1,p2,…,pn of { 1 , 2 , … , n } \{1, 2, \dots, n\} {1,2,…,n} such that B ( s p i − 1 … s n ) < B ( s p i … s n ) B(s_{p_{i - 1}} \dots s_n) < B(s_{p_{i}} \dots s_n) B(spi−1…sn)<B(spi…sn) holds for i = 2 , … , n i = 2, \dots, n i=2,…,n.
The input consists of several test cases terminated by end-of-file.
The first line of each test case contains an integer n.
The second line contains a string s 1 s 2 … s n s_1 s_2 \dots s_n s1s2…sn.
For each test case, print n integers which denote the result.
2
aa
3
aba
5
abaab
2 1
3 2 1
5 4 2 1 3
这题比赛时用的暴力,毫无疑问地超时了,赛后发现可以用后缀数组来解决,考了一个定理:
• Let C i = m i n j > i a n d s j = s i j − i C_i = min_{j > i\ and\ s_j = s_i} {j - i} Ci=minj>i and sj=sij−i
• The B-Suffix Array is equivalent to the suffix array of C 1 C 2 . . . C n C_1 C_2 ... C_n C1C2...Cn
拿第三个样例来说,求出它的 C C C 数组为 231556 231556 231556,注意最后的字符后面默认为 n + 1 n+1 n+1,求出的后缀数组恰为 312456 312456 312456,倒序输出即为答案,但是这题比较麻烦的就是要重写后缀数组的比较函数,因为两个字符之间的位置会很远,以至于超过 ASCILL 码表,所以原来的字符数组必须改为整型数组,重写一下比较函数即可,AC代码如下:
#include
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,c[N];
char s[N];
int rk[N],tmp[N],sa[N],k;
void init(){
k=0;
memset(rk,0,sizeof(rk));
memset(tmp,0,sizeof(tmp));
memset(c,0,sizeof(c));
}
bool cmp(int i,int j){
if(rk[i]!=rk[j]) return rk[i]<rk[j];
else{
int ri,rj;
if(i+k<=n){
ri=rk[i+k];
}
else{
ri=-1;
}
if(j+k<=n){
rj=rk[j+k];
}
else{
rj=-1;
}
return ri<rj;
}
}
void get_sa(int sa[]){
for(int i=0;i<=n;i++){
sa[i]=i;
if(i<n){
rk[i]=c[i];
}
else{
rk[i]=-1;
}
}
for(k=1;k<=n;k*=2){
sort(sa,sa+n+1,cmp);
tmp[sa[0]]=0;
for(int i=1;i<=n;i++){
tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i]) ? 1 : 0);
}
for(int i=0;i<=n;i++){
rk[i]=tmp[i];
}
}
}
int main(){
while(~scanf("%d",&n)){
scanf("%s",s);
int pos1=n,pos2=n;
for(int i=n-1;i>=0;i--){
if(s[i]=='a'){
c[i]=(n-(pos1==n?pos1:pos1-i))%n;
pos1=i;
}else{
c[i]=(n-(pos2==n?pos2:pos2-i))%n;
pos2=i;
}
}
get_sa(sa);
for(int i=1;i<=n;i++) printf("%d ",sa[i]+1);
printf("\n");
}
return 0;
}