2023.12.31做题纪要

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;
}

P2463 [SDOI2008] Sandy 的卡片

\(SAM\) 版:是个板子题???但是要先学会 \(SAM\)\(LCS\)

但是我有个地方少取了个 \(min\) 调了半天QAQ。

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

const int MAXN = 5e3;

int N;

class Suffix_Automaton {
private:
    int root, tot, last;
    std::map<short, int> child[MAXN];
    int length[MAXN], link[MAXN];
    int barrel[MAXN][1100];
public:
    int string[MAXN];

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

    void Insert(int c) {
        int p = last, newP = ++ tot;
        last = newP;
        length[newP] = length[p] + 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;
                child[newQ] = 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];
                }
            }
        }
    }

    void Mate(int rank, int *array, int n) {
        int now = 1, len = 0;
        for (int i = 1; i <= n; ++ i) {
            int next = array[i];
            while (now && !child[now][next]) {
                now = link[now];
                len = length[now];
            }
            if (now) {
                len ++;
                now = child[now][next];
                barrel[now][rank] = std::max(barrel[now][rank], len);
            }
            else {
                now = 1;
                len = 0;
            }
        }
    }

    int degree[MAXN];
    void Build() {
        for (int i = 1; i <= tot; ++ i)
            degree[link[i]] ++;
    }

    int check(int now) {
        int result = 1e9;
        for (int i = 2; i <= N; ++ i) {
            if (!barrel[now][i])
                return 0;
            result = std::min(result, barrel[now][i]);
        }
        return result;
    }

    int Update() {
        std::queue<int> queue;

        for (int i = 1; i <= tot; ++ i)
            if (!degree[i])
                queue.emplace(i);
        while (queue.size()) {
            int now =queue.front();
            int to = link[now];
            queue.pop();

            for (int i = 2; i <= N; ++ i) {
                barrel[to][i] = std::max(std::min(length[to], barrel[now][i]), barrel[to][i]);
                barrel[to][i] = std::min(length[to], barrel[to][i]);
            }
            degree[to] --;
            if (!degree[to])
                queue.emplace(to);
        }

        int result = 0;

        for (int i = 1; i <= tot; ++ i) 
            result = std::max(result, check(i));

        return result + 1;
    }
}sam;

int a[1100], differ[1100];

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

    std::cin >> N;
    for (int i = 1, M; i <= N; ++ i) {
        std::cin >> M;
        for (int j = 1; j <= M; ++ j) {
            std::cin >> a[j];
            if (j >= 2) {
                differ[j - 1] = a[j] - a[j - 1];
            }
        }
        if (i == 1) 
            for (int j = 1; j <= M - 1; ++ j) 
                sam.Insert(differ[j]);
        else 
            sam.Mate(i, differ, M - 1);
    }

    sam.Build();
    std::cout << sam.Update() << '\n';

    return 0;
}
posted @ 2023-12-31 10:50  觉清风  阅读(23)  评论(4编辑  收藏  举报