2023.12.31做题纪要

发布时间 2023-12-31 10:53:23作者: 觉清风

TJOI2015 弦论

身为彩笔的我觉得这道题还不错???对于新学的我来说挺考验对 \(SAM\) 的理解??

要用一个类似洛谷 \(SAM\) 板子题的数组来记录每个节点的 \(right(endpos)\) 集合的大小。

最后维护一下就行了。主要难在证明。

晴天
#include <bits/stdc++.h>

const int MAXN = 3 * (5e5 + 100);

int N, T, K;
char ch[MAXN];

class Suffix_Automaton {
public:
    int repeat[MAXN];
private:
    void Insert(int c) {
        int p = last, newP = ++ tot;
        last = newP; 
        length[newP] = length[p] + 1;
        repeat[newP] = 1;

        while (p && !child[p][c]) {
            child[p][c] = newP;
            p = link[p];
        }
        if (!p) {
            link[newP] = root;
        }
        else {
            int q = child[p][c];
            if (length[q] == length[p] + 1) {
                link[newP] = q;
            }
            else {
                int newQ = ++ tot;
                memcpy(child[newQ], child[q], sizeof child[q]);
                link[newQ] = link[q];
                link[q] = link[newP] = newQ;
                length[newQ] = length[p] + 1;

                while (p && child[p][c] == q) {
                    child[p][c] = newQ;
                    p = link[p];
                }
            }
        }
    }

public:
    char string[MAXN];
    int tot, last, root;
    int child[MAXN][27], link[MAXN], length[MAXN];
    int count[MAXN];

    Suffix_Automaton() {
        root = tot = last = 1;
    }

    void Treat() {
        int N = strlen(string + 1);
        for (int i = 1; i <= N; ++ i)
            Insert(string[i] - 'a' + 1);
    }

    std::vector<int> son[MAXN];
    void Build() {
        for (int i = 1; i <= tot; ++ i) {
            son[link[i]].emplace_back(i);
        }
    }

    void Dfs(int now) {
        for (const int &iter: son[now]) {
            Dfs(iter);
            repeat[now] += repeat[iter];
        }
    }
}sam;

bool visit[MAXN];

int Dfs(int now) {
    if (visit[now]) 
        return sam.count[now];
    if (T == 0)
        sam.repeat[now] = 1;
    sam.count[now] = sam.repeat[now];
    visit[now] = true;
    for (int i = 1; i <= 26; ++ i) {
        if (!sam.child[now][i])
            continue;
        sam.count[now] += Dfs(sam.child[now][i]);
    }
    return sam.count[now];
}

std::vector<char> answer;

void GetAnswer(int now, int rest) {
    rest -= sam.repeat[now];
    if (rest == 0)
        return;
    for (int i = 1; i <= 26; ++ i) {
        int to = sam.child[now][i];
        if (!to)
            continue;
        if (rest - sam.count[to] <= 0) {
            answer.emplace_back('a' + i - 1);
            GetAnswer(to, rest);
            return;
        }
        rest -= sam.count[to];
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    std::cin >> (sam.string + 1);
    std::cin >> T >> K;

    sam.Treat();
    if (T == 1) {
        sam.Build();
        sam.Dfs(1);
    }
    Dfs(1);
    GetAnswer(1, K + sam.repeat[1]);
    if (!answer.size()) {
        std::cout << -1 << '\n';
        return 0;
    }
    for (const char &iter: answer)
        std::cout << iter;
    std::cout << '\n';
    return 0;
}