Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。Input
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1Sample Input
aabc
0 3
Sample Output
aabHINT
N<=5*10^5
T<2
K<=10^9
其实就是SAM裸题吧..
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int Maxn = 500010;
int F[Maxn*2], d[Maxn*2], ch[Maxn*2][26], f[Maxn*2], val[Maxn*2], tot, now;
int Rsort[Maxn*2], rk[Maxn*2];
char s[Maxn]; int len;
int t, K;
int copy ( int p, int c ){
int x = ++tot, y = ch[p][c];
d[x] = d[p]+1;
for ( int i = 0; i < 26; i ++ ) ch[x][i] = ch[y][i];
F[x] = F[y]; F[y] = x;
while ( ~p && ch[p][c] == y ){ ch[p][c] = x; p = F[p]; }
return x;
}
void add ( int c ){
int p, o;
if ( p = ch[now][c] ){
if ( d[p] != d[now]+1 ) copy ( now, c );
now = ch[now][c];
}
else {
d[o=++tot] = d[now]+1; p = now; now = o; f[o] = 1;
while ( ~p && !ch[p][c] ){ ch[p][c] = o; p = F[p]; }
F[o] = ~p ? ( d[p]+1 == d[ch[p][c]] ? ch[p][c] : copy ( p, c ) ) : 0;
}
}
int main (){
int i, j, k;
scanf ( "%s", s+1 ); len = strlen (s+1);
F[0] = -1;
scanf ( "%d%d", &t, &K );
for ( i = 1; i <= len; i ++ ) add (s[i]-'a');
for ( i = 1; i <= tot; i ++ ) Rsort[d[i]] ++;
for ( i = 1; i <= len; i ++ ) Rsort[i] += Rsort[i-1];
for ( i = tot; i >= 1; i -- ) rk[Rsort[d[i]]--] = i;
for ( i = tot; i >= 1; i -- ){
if ( t == 1 ) f[F[rk[i]]] += f[rk[i]];
else f[rk[i]] = 1;
val[rk[i]] = f[rk[i]];
}
for ( i = tot; i >= 1; i -- ){
for ( j = 0; j < 26; j ++ ) if ( ch[rk[i]][j] > 0 ) f[rk[i]] += f[ch[rk[i]][j]];
}
for ( i = 0; i < 26; i ++ ){
if ( ch[0][i] ){
f[0] += f[ch[0][i]];
}
}
if ( K > f[0] ){ printf ( "-1\n" ); return 0; }
now = 0;
while ( K > 0 ){
K -= val[now];
if ( K <= 0 ) break;
for ( i = 0; i < 26; i ++ ){
if ( ch[now][i] ){
if ( K <= f[ch[now][i]] ){
printf ( "%c", i+'a' );
now = ch[now][i];
break;
}
else K -= f[ch[now][i]];
}
}
}
printf ( "\n" );
return 0;
}