vector< int > suffix_array( string s)
{
int n = s.size ( ) ;
vector< int > sa( n) , rank( n) ;
for ( int i = 0 ; i < n; i++ )
rank[ i] = s[ i] ,
sa[ i] = i;
for ( int k = 0 ; k < n; k ? k * = 2 : k = 1 )
{
stable_sort( sa.begin ( ) , sa.end ( ) , [ & ] ( int i, int j)
{
if ( rank[ i] == rank[ j] )
return rank[ ( i + k) % n] < rank[ ( j + k) % n] ;
return rank[ i] < rank[ j] ;
} ) ;
vector< int > nrank( n) ;
int r = 0 ;
for ( int i = 1 ; i < n; i++ )
{
if ( rank[ sa[ i] ] ! = rank[ sa[ i - 1 ] ] ) r++ ;
else if ( rank[ ( sa[ i] + k) % n] ! = rank[ ( sa[ i - 1 ] + k) % n] ) r++ ;
nrank[ sa[ i] ] = r;
}
rank = nrank;
}
return sa;
}
vector< int > kasai( string s, vector< int > sa)
{
int n = s.size ( ) , k = 0 ;
vector< int > ra( n) , lcp( n) ;
for ( int i = 0 ; i < n; i++ ) ra[ sa[ i] ] = i;
for ( int i = 0 ; i < n; i++ )
{
if ( k) k-- ;
if ( ra[ i] == n - 1 ) { k = 0 ; continue ; }
int j = sa[ ra[ i] + 1 ] ;
while ( k < n && s[ ( i + k) % n] == s[ ( j + k) % n] ) k++ ;
lcp[ ra[ i] ] = k;
if ( ra[ ( sa[ ra[ i] ] + 1 ) % n] > ra[ ( sa[ ra[ j] ] + 1 ) % n] ) k = 0 ;
}
return lcp;
}
CnZlY3RvcjxpbnQ+IHN1ZmZpeF9hcnJheShzdHJpbmcgcykKewogICAgaW50IG4gPSBzLnNpemUoKTsKICAgIHZlY3RvcjxpbnQ+IHNhKG4pLCByYW5rKG4pOwogICAgZm9yKGludCBpID0gMDsgaSA8IG47IGkrKykKICAgICAgICByYW5rW2ldID0gc1tpXSwKICAgICAgICBzYVtpXSA9IGk7CiAgICBmb3IoaW50IGsgPSAwOyBrIDwgbjsgayA/IGsgKj0gMiA6IGsgPSAxKQogICAgewogICAgICAgIHN0YWJsZV9zb3J0KHNhLmJlZ2luKCksIHNhLmVuZCgpLCBbJl0oaW50IGksIGludCBqKQogICAgICAgICAgICAgewogICAgICAgICAgICAgICAgIGlmKHJhbmtbaV0gPT0gcmFua1tqXSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmFua1soaSArIGspICUgbl0gPCByYW5rWyhqICsgaykgJSBuXTsKICAgICAgICAgICAgICAgICByZXR1cm4gcmFua1tpXSA8IHJhbmtbal07CiAgICAgICAgICAgICB9KTsKICAgICAgICB2ZWN0b3I8aW50PiBucmFuayhuKTsKICAgICAgICBpbnQgciA9IDA7CiAgICAgICAgZm9yKGludCBpID0gMTsgaSA8IG47IGkrKykKICAgICAgICB7CiAgICAgICAgICAgIGlmKHJhbmtbc2FbaV1dICE9IHJhbmtbc2FbaSAtIDFdXSkgcisrOwogICAgICAgICAgICBlbHNlIGlmKHJhbmtbKHNhW2ldICsgaykgJSBuXSAhPSByYW5rWyhzYVtpIC0gMV0gKyBrKSAlIG5dKSByKys7CiAgICAgICAgICAgIG5yYW5rW3NhW2ldXSA9IHI7CiAgICAgICAgfQogICAgICAgIHJhbmsgPSBucmFuazsKICAgIH0KICAgIHJldHVybiBzYTsKfQoKdmVjdG9yPGludD4ga2FzYWkoc3RyaW5nIHMsIHZlY3RvcjxpbnQ+IHNhKQp7CiAgICBpbnQgbiA9IHMuc2l6ZSgpLCBrID0gMDsKICAgIHZlY3RvcjxpbnQ+IHJhKG4pLCBsY3Aobik7CiAgICBmb3IoaW50IGkgPSAwOyBpIDwgbjsgaSsrKSByYVtzYVtpXV0gPSBpOwogICAgZm9yKGludCBpID0gMDsgaSA8IG47IGkrKykKICAgIHsKICAgICAgICBpZihrKSBrLS07CiAgICAgICAgaWYocmFbaV0gPT0gbiAtIDEpIHtrID0gMDsgY29udGludWU7fQogICAgICAgIGludCBqID0gc2FbcmFbaV0gKyAxXTsKICAgICAgICB3aGlsZShrIDwgbiAmJiBzWyhpICsgaykgJSBuXSA9PSBzWyhqICsgaykgJSBuXSkgaysrOwogICAgICAgIGxjcFtyYVtpXV0gPSBrOwogICAgICAgIGlmKHJhWyhzYVtyYVtpXV0gKyAxKSAlIG5dID4gcmFbKHNhW3JhW2pdXSArIDEpICUgbl0pIGsgPSAwOwogICAgfQogICAgcmV0dXJuIGxjcDsKfQ==