3998: [TJOI2015]弦论
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 3292 Solved: 1133
[ Submit][ Status][ Discuss]
Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。
Input
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
Sample Input
aabc
0 3
0 3
Sample Output
aab
HINT
N<=5*10^5
T<2
K<=10^9
Source
以前wjj给我讲过但那是暑假的事了... 现在几乎都忘光了... 不过重拾起来还是非常快? 虽然一开始看毛子论文的各种专业术语乱飚一脸懵逼, 不过努力回想wjj讲过的内容在纸上推推还是推出来了... 明白了以后看了下clj神犇的论文发现这玩意性质还非常多? 感觉比今早上学的回文自动机要高级多了... 看来还是得多学习一个... 争取深入理解后缀自动机, 把性质都记录下来推一推多做点题.
这道题很简单, 两种情况分类讨论逆拓扑序倒推预处理, 然后询问第k大可以说是...26分?
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1000005;
char ss[maxn];
int n, k, T, cnt = 1, last = 1;
int ws[maxn], sa[maxn], c[maxn][26], dep[maxn], val[maxn], sum[maxn], par[maxn];
struct sam{
inline void build(int x) {
int p = last, np = last = ++ cnt;
dep[np] = dep[p] + 1; val[np] = 1;
while (p && !c[p][x]) c[p][x] = np, p = par[p];
if (!p) par[np] = 1;
else {
int who = c[p][x];
if (dep[who] == dep[p] + 1) par[np] = who;
else {
int anwho = ++ cnt;
dep[anwho] = dep[p] + 1;
memcpy(c[anwho], c[who], sizeof(c[who]));
par[anwho] = par[who];
par[np] = par[who] = anwho;
while (c[p][x] == who) c[p][x] = anwho, p = par[p];
}
}
}
inline void init() {
for (int i = 1; i <= cnt; ++ i) ws[dep[i]] ++;
for (int i = 1; i <= n; ++ i) ws[i] += ws[i - 1];
for (int i = cnt; i; -- i) sa[ws[dep[i]]--] = i;
for (int i = cnt; i; -- i) {
int t = sa[i];
if (T & 1) val[par[t]] += val[t];
else val[t] = 1;
}
val[1] = 0;
for (int i = cnt; i; -- i) {
int t = sa[i]; sum[t] = val[t];
for (int ch = 0; ch < 26; ++ ch)
sum[t] += sum[c[t][ch]];
}
}
void calc(int x,int k) {
while(true) {
if (k <= val[x]) return;
k -= val[x];
for (int i = 0; i < 26; ++ i) {
int t = c[x][i];
if (t) {
if (k <= sum[t]) {
putchar(i + 'a');
x = t;
break;
}
k -= sum[t];
}
}
}
}
}sam;
int main() {
scanf("%s", ss + 1);
n = strlen(ss + 1);
scanf("%d%d", &T, &k);
for (int i = 1; i <= n; ++ i) sam.build(ss[i] - 'a');
sam.init();
if (k > sum[1]) puts("-1");
else sam.calc(1,k);
return 0;
}