【UVALive】7502 Suffixes and Palindromes【根据sa数组以及回文半径数组构造字典序最小的串】

题目链接:【UVALive】7502 Suffixes and Palindromes

根据回文半径数组能得出一堆不等相等关系,相等缩点,不等建边。
根据sa数组的对偶数组rank数组的性质,考虑sa[i]和sa[i-1],如果如果rank[sa[i]+1]>rank[sa[i-1]+1]则s[sa[i]]可以等于s[sa[i-1]];如果rank[sa[i]+1]>rank[sa[i-1]+1]则s[sa[i]]必须大于s[sa[i-1]]。
根据以上信息可以得出字典序最小的串。

#include 
using namespace std ;

const int MAXN = 200005 ;
const int MAXE = 610005 ;

struct Edge {
    int v , n ;
    Edge () {}
    Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;

Edge E[MAXE] ;
int H[MAXN] , H2[MAXN] , cntE ;
int f[MAXN] , R[MAXN] ;
int sa[MAXN] , rnk[MAXN] ;
int p[MAXN] ;
char col[MAXN] ;
int n , m ;

void addedge ( int u , int v ) {
    E[cntE] = Edge ( v , H[u] ) ;
    H[u] = cntE ++ ;
}

void addedge2 ( int u , int v ) {
    E[cntE] = Edge ( v , H2[u] ) ;
    H2[u] = cntE ++ ;
}

int Wrong () {
    return printf ( "Wrong calculation!\n" ) ;
}

int F ( int x ) {
    return p[x] == x ? x : ( p[x] = F ( p[x] ) ) ;
}

int make_same ( int x , int y ) {
    if ( x <= 0 || y >= m ) return 0 ;
    if ( x % 2 != y % 2 ) return 0 ;
    //printf ( "same %d %d\n" , x , y ) ;
    p[F ( x )] = F ( y ) ;
    return 1 ;
}

int make_diff ( int x , int y ) {
    if ( x < 0 || y > m ) return 0 ;
    if ( x == 0 || y == m ) return 1 ;
    if ( x % 2 == 1 && y % 2 == 1 ) return 0 ;
    if ( F ( x ) == F ( y ) ) return 0 ;
    addedge ( x , y ) ;
    //printf ( "diff %d %d\n" , x , y ) ;
    return 1 ;
}

int solve () {
    scanf ( "%d" , &n ) ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        scanf ( "%d" , &sa[i] ) ;
        rnk[++ sa[i]] = i ;
    }
    rnk[n + 1] = 0 ;
    for ( int i = 2 ; i <= n * 2 ; ++ i ) {
        scanf ( "%d" , &R[i] ) ;
        ++ R[i] ;
    }
    m = ( n + 1 ) << 1 ;
    R[1] = R[m - 1] = f[1] = 1 ;
    cntE = 0 ;
    for ( int i = 0 ; i < m ; ++ i ) {
        p[i] = i ;
        col[i] = 0 ;
        H[i] = H2[i] = -1 ;
    }
    for ( int i = 2 , r = 0 , pos = 0 ; i < m ; ++ i ) {
        for ( f[i] = r > i ? min ( r - i , f[pos * 2 - i] ) : 1 ; f[i] < R[i] ; ++ f[i] ) {
            if ( !make_same ( i - f[i] , i + f[i] ) ) return Wrong () ;
        }
        if ( f[i] > R[i] ) return Wrong () ;
        if ( !make_diff ( i - f[i] , i + f[i] ) ) return Wrong () ;
        if ( i + f[i] > r ) r = i + f[i] , pos = i ;
    }
    for ( int i = 0 ; i < m ; ++ i ) F ( i ) ;
    for ( int i = 0 ; i < m ; ++ i ) {
        for ( int j = H[i] ; ~j ; j = E[j].n ) {
            if ( p[i] == p[E[j].v] ) return Wrong () ;
            addedge2 ( p[i] , p[E[j].v] ) ;
            addedge2 ( p[E[j].v] , p[i] ) ;
        }
    }
    int color = 'a' ;
    col[p[sa[1] << 1]] = color ;
    for ( int i = 2 ; i <= n ; ++ i ) {
        int x = sa[i] << 1 , y = sa[i - 1] << 1 , cansame = 1 ;
        if ( rnk[sa[i] + 1] < rnk[sa[i - 1] + 1] ) cansame = 0 ;
        //printf ( "cansame = %d\n" , cansame ) ;
        if ( col[p[x]] ) {
            if ( cansame && col[p[x]] < col[p[y]] ) return Wrong () ;
            else if ( !cansame && col[p[x]] <= col[p[y]] ) return Wrong () ;
        } else {
            for ( int j = H2[p[x]] ; ~j ; j = E[j].n ) if ( col[E[j].v] == color ) cansame = 0 ;
            if ( !cansame ) ++ color ;
            if ( color > 'z' ) return Wrong () ;
            col[p[x]] = color ;
        }
    }
    for ( int i = 1 ; i <= n ; ++ i ) printf ( "%c" , col[p[i << 1]] ) ;
    puts ( "" ) ;
}

int main () {
    int T ;
    scanf ( "%d" , &T ) ;
    for ( int i = 1 ; i <= T ; ++ i ) {
        printf ( "Case #%d: " , i ) ;
        solve () ;
    }
    return 0 ;
}

你可能感兴趣的:(manacher,后缀数组【SA】)