【题解】【LOJ2102】「TJOI2015」弦论

题目链接

点击打开链接

题目解法

后缀自动机入门题。

建立后缀自动机。求第 \(k\) 大可以考虑按位确定。把后缀自动机当成一个 trie 树看,每次类似于平衡树上查找第 k 大的方式查找即可。

总结

没啥。

代码

#include 
#include 
using namespace std;
const int CN = 5e5 + 5, CNODE = 1e6 + 5;
struct SAM {
    int edge[26], parent, len, size;
    bool leaf;
} node[CNODE];
int last, ntot, N, T, K, topo[CNODE], buc[CN], num[2][CNODE];
int cnt = 0;
void Extend(int c) {
    ++cnt;
    int p = last, newnode = ++ntot;
    node[newnode].len = node[last].len + 1;
    //先计算 newnode的 len,再将 last变成 newnode
    last = newnode;
    node[newnode].leaf = 1;
    for (; p && node[p].edge[c] == 0; p = node[p].parent) node[p].edge[c] = newnode;
    if (!p)
        node[newnode].parent = 1;
    else {
        int q = node[p].edge[c];
        if (node[q].len == node[p].len + 1)
            node[newnode].parent = q;
        else {
            int clone = ++ntot;
            for (int i = 0; i < 26; ++i) node[clone].edge[i] = node[q].edge[i];
            node[clone].leaf = 0;
            // clone的 endpos
            node[clone].parent = node[q].parent;
            node[clone].len = node[p].len + 1;
            node[q].parent = node[newnode].parent = clone;
            for (; p && node[p].edge[c] == q; p = node[p].parent) node[p].edge[c] = clone;
        }
    }
}
void GetSize() {
    for (int i = 1; i <= ntot; ++i) ++buc[node[i].len];
    for (int i = 1; i <= N; ++i) buc[i] += buc[i - 1];
    for (int i = 1; i <= ntot; ++i) {
        topo[buc[node[i].len]--] = i;
        node[i].size = node[i].leaf;
    }
    for (int i = ntot; i >= 1; --i) {
        node[node[topo[i]].parent].size += node[topo[i]].size;
        if (topo[i] != 1) {
            num[0][topo[i]] = 1;
            num[1][topo[i]] = node[topo[i]].size;
        }
        for (int j = 0; j < 26; ++j) {
            if (node[topo[i]].edge[j]) {
                num[0][topo[i]] += num[0][node[topo[i]].edge[j]];
                num[1][topo[i]] += num[1][node[topo[i]].edge[j]];
            }
        }
    }
}
void Find() {
    int now = 1;
    node[1].size = 0;
    if (T == 0)
        for (int i = 2; i <= ntot; ++i) node[i].size = 1;
    num[T][1] = 0;
    while (K > node[now].size) {
        for (int i = 0; i < 26; ++i) {
            if (!node[now].edge[i])
                continue;
            if (K <= num[T][node[now].edge[i]]) {
                K -= node[now].size;
                now = node[now].edge[i];
                printf("%c", (char)i + 'a');
                break;
            } else
                K -= num[T][node[now].edge[i]];
        }
    }
    printf("\n");
}
char str[CN];
int main() {
    scanf("%s%d%d", str + 1, &T, &K);
    N = strlen(str + 1);
    last = ntot = 1;
    for (int i = 1; i <= N; ++i) Extend(str[i] - 'a');
    GetSize();
    if (num[T][1] < K)
        printf("-1\n");
    else
        Find();
    return 0;
}

你可能感兴趣的:(【题解】【LOJ2102】「TJOI2015」弦论)