【SPOJ 7258】Lexicographical Substring Search

http://www.spoj.com/problems/SUBLEX/

好难啊。

建出后缀自动机,然后在后缀自动机的每个状态上记录通过这个状态能走到的不同子串的数量。该状态能走到的所有状态的f值的和+1就是当前状态的f值。

最后对于询问的k,从root开始走顺便加加减减就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int in() {
int k = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar());
for(; c >= '0' && c <= '9'; c = getchar())
k = k * 10 + c - 48;
return k;
} int tot = 0, par[250003], go[250003][26], val[250003], f[250003], root, last; void extend(int w) {
int p = last;
int np = ++tot; val[np] = val[p] + 1;
while (p && go[p][w] == 0)
go[p][w] = np, p = par[p];
if (p == 0) par[np] = root;
else {
int q = go[p][w];
if (val[q] == val[p] + 1) par[np] = q;
else {
int nq = ++tot; val[nq] = val[p] + 1;
memcpy(go[nq], go[q], sizeof(go[q]));
par[nq] = par[q];
par[q] = par[np] = nq;
while (p && go[p][w] == q)
go[p][w] = nq, p = par[p];
}
}
last = np;
} char s[150003];
int len, Q, k, c[150003], id[250003], tmp; int main() {
root = last = ++tot;
scanf("%s", s + 1);
len = strlen(s + 1);
for(int i = 1; i <= len; ++i)
extend(s[i] - 'a'); for(int i = 1; i <= tot; ++i)
++c[val[i]];
for(int i = 1; i <= len; ++i)
c[i] += c[i - 1];
for(int i = tot; i >= 1; --i)
id[c[val[i]]--] = i; int sum, x;
for(int i = tot; i >= 1; --i) {
sum = 0; x = id[i];
for(int j = 0; j < 26; ++j)
sum += f[go[x][j]];
f[x] = sum + 1;
} Q = in();
while (Q--) {
k = in();
tmp = root;
while (k) {
for(int i = 0; i < 26; ++i)
if (x = go[tmp][i])
if (f[x] >= k) {
putchar('a' + i);
--k;
tmp = x;
break;
} else
k -= f[x];
}
puts("");
}
return 0;
}
上一篇:Dynamics CRM 后台通过组织服务获取时间字段值的准确转换


下一篇:linux之cut用法