2020牛客暑期多校训练营(第一场)A.B-Suffix Array

2020牛客暑期多校训练营(第一场)A.B-Suffix Array

题目链接

题目描述

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(t1t2tk)=b1b2bk of a string t 1 t 2 … t k t_1 t_2 \dots t_k t1t2tk is defined as follows.

  • If there is an index j < i where t j = t i t_j = t_i tj=ti, b i = min ⁡ 1 ≤ j < i , t j = t i { i − j } b_i = \min_{1 \leq j < i, t_j = t_i}\{i - j\} bi=min1j<i,tj=ti{ij}
  • Otherwise, b i = 0 b_i = 0 bi=0.

Given a string s 1 s 2 … s n s_1 s_2 \dots s_n s1s2sn, 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(spi1sn)<B(spisn) 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 s1s2sn.

  • 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^{5} 1n105
  • s i s_i si is either ‘a’ or ‘b’
  • The sum of n does not exceed 1 0 6 10^{6} 106

输出描述:

For each test case, print n integers which denote the result.

示例1

输入

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=siji
• 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;
}

你可能感兴趣的:(后缀数组,牛客)