首页 > 其他分享 >Solution Set【2023.12.28】

Solution Set【2023.12.28】

时间:2023-12-28 22:11:57浏览次数:49  
标签:std ch 2023.12 valueType 28 Set Link Transfer New

[NOI2015] 品酒大会

若建出后缀树,我们可以发现,产生贡献的是每个点对。考虑在其最近公共祖先处统计答案。

因此对于每个点,我们需要统计其子树中每个权值的最大值和最小值,以及子树大小即可解出答案。

使用后缀自动机建出后缀树,然后统计即可。

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::string string;
typedef std::vector<bool> bitset;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;

constexpr valueType MIN = std::numeric_limits<valueType>::min(), MAX = std::numeric_limits<valueType>::max();

class SuffixAutomaton {
public:
    constexpr static valueType CharSetSize = 26;
    typedef std::array<valueType, CharSetSize> TransferMap;
    typedef std::vector<TransferMap> TransferMatrix;

private:
    // main data
    valueType N, UsedPoolSize;
    ValueVector Link, Length;
    TransferMatrix Transfer;
    bitset Cloned;

    // maybe useful
    ValueVector TopoOrder;

    // data for function extend
    valueType Last;

    // customed data for selected problems (P4248)
    ValueVector EndPosCount;
    ValueMatrix ParentTree;
    // PairVector Min /*first min, second min*/, Max /*first max, second max*/;
    ValueVector Min, Max;

public:
    SuffixAutomaton() = default;

    explicit SuffixAutomaton(valueType n) : N(n), UsedPoolSize(0), Link(2 * N + 1), Length(2 * N + 1), Transfer(2 * N + 1), Cloned(2 * N + 1, false), Last(0), Min(2 * N + 1, MAX), Max(2 * N + 1, MIN) {
        Link[0] = -1;

        for (auto &p : Transfer)
            p.fill(0);
    }

    void extend(char ch, valueType w) {
        ch = ch - 'a';

        valueType New = ++UsedPoolSize;

        Length[New] = Length[Last] + 1;
        Min[New] = Max[New] = w;

        valueType P = Last;

        Last = New;

        while (P != -1 && !Transfer[P][ch]) {
            Transfer[P][ch] = New;

            P = Link[P];
        }

        if (P == -1) {
            Link[New] = 0;
        } else {
            valueType Q = Transfer[P][ch];

            if (Length[P] + 1 == Length[Q]) {
                Link[New] = Q;
            } else {
                valueType Clone = ++UsedPoolSize;

                Cloned[Clone] = true;

                Length[Clone] = Length[P] + 1;
                Link[Clone] = Link[Q];
                Transfer[Clone] = Transfer[Q];

                while (P != -1 && Transfer[P][ch] == Q) {
                    Transfer[P][ch] = Clone;

                    P = Link[P];
                }

                Link[Q] = Link[New] = Clone;
            }
        }
    }

public:
    // extra functions
    void GetTopoOrder() {
        TopoOrder.resize(UsedPoolSize + 1);

        ValueVector bucket(N + 1, 0);

        for (valueType i = 0; i <= UsedPoolSize; ++i)
            ++bucket[Length[i]];

        for (valueType i = 1; i <= N; ++i)
            bucket[i] += bucket[i - 1];

        for (valueType i = 0; i <= UsedPoolSize; ++i)
            TopoOrder[--bucket[Length[i]]] = i;

        std::reverse(TopoOrder.begin(), TopoOrder.end());
    }

public:
    // customed functions for selected problems (P2178)
    std::pair<ValueVector, ValueVector> Ans() {
        ValueVector MaxAns(N + 1, MIN), SumAns(N + 1, 0);

        EndPosCount.resize(UsedPoolSize + 1, 0);
        ParentTree.resize(UsedPoolSize + 1);

        for (valueType i = 1; i <= UsedPoolSize; ++i)
            if (!Cloned[i])
                EndPosCount[i] = 1;

        for (auto const &u : TopoOrder) {
            if (Link[u] != -1)
                ParentTree[Link[u]].push_back(u);
        }

        for (auto const &u : TopoOrder) {
            if (ParentTree[u].empty())
                continue;

            for (auto const &v : ParentTree[u]) {
                if (Max[v] != MIN && Max[u] != MIN)
                    MaxAns[Length[u]] = std::max(MaxAns[Length[u]], Max[v] * Max[u]);

                if (Min[v] != MAX && Min[u] != MAX)
                    MaxAns[Length[u]] = std::max(MaxAns[Length[u]], Min[v] * Min[u]);

                Max[u] = std::max(Max[u], Max[v]);
                Min[u] = std::min(Min[u], Min[v]);

                SumAns[Length[u]] += EndPosCount[u] * EndPosCount[v];

                EndPosCount[u] += EndPosCount[v];
            }
        }

        for (valueType i = N - 1; i >= 0; --i) {
            SumAns[i] += SumAns[i + 1];
            MaxAns[i] = std::max(MaxAns[i], MaxAns[i + 1]);
        }

        for (auto &p : MaxAns)
            if (p == MIN)
                p = 0;

        return std::make_pair(MaxAns, SumAns);
    }
};

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

    valueType N;

    std::cin >> N;

    std::string S;

    std::cin >> S;

    ValueVector W(N);

    for (auto &p : W)
        std::cin >> p;

    std::reverse(S.begin(), S.end());
    std::reverse(W.begin(), W.end());

    SuffixAutomaton SAM(N);

    for (valueType i = 0; i < N; ++i)
        SAM.extend(S[i], W[i]);

    SAM.GetTopoOrder();

    auto [MaxAns, SumAns] = SAM.Ans();

    for (valueType i = 0; i < N; ++i)
        std::cout << SumAns[i] << ' ' << MaxAns[i] << '\n';

    std::cout << std::flush;

    return 0;
}

[AHOI2013] 差异

将题目中的算式放到后缀树中考虑,发现其实就是求后缀树中每个点对的带权距离。

考虑计算每条边的贡献,即每条边的权值乘上其两端点的子树大小之积。

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::string string;
typedef std::vector<bool> bitset;

class SuffixAutomaton {
public:
    constexpr static valueType CharSetSize = 26;
    typedef std::array<valueType, CharSetSize> TransferMap;
    typedef std::vector<TransferMap> TransferMatrix;

private:
    // main data
    valueType N, UsedPoolSize;
    ValueVector Link, Length;
    TransferMatrix Transfer;
    bitset Cloned;

    // maybe useful
    ValueVector TopoOrder;

    // data for function extend
    valueType Last;

public:
    SuffixAutomaton() = default;

    explicit SuffixAutomaton(valueType n) : N(n), UsedPoolSize(0), Link(2 * N + 1), Length(2 * N + 1), Transfer(2 * N + 1), Cloned(2 * N + 1, false), Last(0) {
        Link[0] = -1;

        for (auto &p : Transfer)
            p.fill(0);
    }

    explicit SuffixAutomaton(string const &s) : SuffixAutomaton(s.size()) {
        for (auto const &ch : s)
            extend(ch);
    }

    void extend(char ch) {
        ch = ch - 'a';

        valueType New = ++UsedPoolSize;

        Length[New] = Length[Last] + 1;

        valueType P = Last;

        Last = New;

        while (P != -1 && !Transfer[P][ch]) {
            Transfer[P][ch] = New;

            P = Link[P];
        }

        if (P == -1) {
            Link[New] = 0;
        } else {
            valueType Q = Transfer[P][ch];

            if (Length[P] + 1 == Length[Q]) {
                Link[New] = Q;
            } else {
                valueType Clone = ++UsedPoolSize;

                Cloned[Clone] = true;

                Length[Clone] = Length[P] + 1;
                Link[Clone] = Link[Q];
                Transfer[Clone] = Transfer[Q];

                while (P != -1 && Transfer[P][ch] == Q) {
                    Transfer[P][ch] = Clone;

                    P = Link[P];
                }

                Link[Q] = Link[New] = Clone;
            }
        }
    }

public:
    // extra functions
    void GetTopoOrder() {
        TopoOrder.resize(UsedPoolSize + 1);

        ValueVector bucket(N + 1, 0);

        for (valueType i = 0; i <= UsedPoolSize; ++i)
            ++bucket[Length[i]];

        for (valueType i = 1; i <= N; ++i)
            bucket[i] += bucket[i - 1];

        for (valueType i = 0; i <= UsedPoolSize; ++i)
            TopoOrder[--bucket[Length[i]]] = i;

        std::reverse(TopoOrder.begin(), TopoOrder.end());
    }

public:
    // customed functions for selected problems (P4248)
    valueType Ans() const {
        valueType ans = 0;

        ValueVector EndPosCount(UsedPoolSize + 1, 0);

        for (valueType i = 1; i <= UsedPoolSize; ++i)
            if (!Cloned[i])
                EndPosCount[i] = 1;

        for (auto const &u : TopoOrder) {
            if (Link[u] != -1)
                EndPosCount[Link[u]] += EndPosCount[u];
        }

        for (auto const &u : TopoOrder) {
            if (Link[u] != -1)
                ans += EndPosCount[u] * (EndPosCount[0] - EndPosCount[u]) * (Length[u] - Length[Link[u]]);
        }

        return ans;
    }
};

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

    std::string S;

    std::cin >> S;

    std::reverse(S.begin(), S.end());

    SuffixAutomaton SAM(S);

    SAM.GetTopoOrder();

    std::cout << SAM.Ans() << std::endl;

    return 0;
}

【模板】广义后缀自动机(广义 SAM)

将所有字符串插入字典树,然后按字典树的拓扑序依次将节点插入后缀自动机中即可。

Code
#include <bits/stdc++.h>

typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::string string;
typedef std::vector<bool> bitset;

class GeneralSuffixAutomaton {
public:
    constexpr static valueType CharSetSize = 26;
    typedef std::array<valueType, CharSetSize> TransferMap;
    typedef std::vector<TransferMap> TransferMatrix;

private:
    valueType N, UsedPoolSize;
    ValueVector Link, Length;
    TransferMatrix Transfer;
    bitset Cloned;

private:
    valueType insertOnTrie(valueType current, valueType ch) {
        if (Transfer[current][ch])
            return Transfer[current][ch];
        else
            return Transfer[current][ch] = ++UsedPoolSize;
    }

    valueType expand(valueType Last, valueType ch) {
        valueType New = Transfer[Last][ch];

        if (Length[New] != 0)
            return New;

        Length[New] = Length[Last] + 1;

        valueType P = Link[Last];

        while (P != -1 && !Transfer[P][ch]) {
            Transfer[P][ch] = New;

            P = Link[P];
        }

        if (P == -1) {
            Link[New] = 0;
        } else {
            valueType Q = Transfer[P][ch];

            if (Length[P] + 1 == Length[Q]) {
                Link[New] = Q;
            } else {
                valueType Clone = ++UsedPoolSize;

                Length[Clone] = Length[P] + 1;
                Link[Clone] = Link[Q];

                for (valueType i = 0; i < CharSetSize; ++i)
                    Transfer[Clone][i] = Length[Transfer[Q][i]] != 0 ? Transfer[Q][i] : 0;

                Cloned[Clone] = true;

                while (P != -1 && Transfer[P][ch] == Q) {
                    Transfer[P][ch] = Clone;

                    P = Link[P];
                }

                Link[Q] = Link[New] = Clone;
            }
        }

        return New;
    }

public:
    GeneralSuffixAutomaton() = default;

    explicit GeneralSuffixAutomaton(valueType n) : N(n), UsedPoolSize(0), Link(2 * N + 1), Length(2 * N + 1), Transfer(2 * N + 1), Cloned(2 * N + 1, false) {
        Link[0] = -1;

        for (auto &p : Transfer)
            p.fill(0);
    }

    void insert(string const &s) {
        valueType current = 0;

        for (auto ch : s)
            current = insertOnTrie(current, ch - 'a');
    }

    void insert(ValueVector const &s) {
        valueType current = 0;

        for (auto ch : s)
            current = insertOnTrie(current, ch);
    }

    void build() {
        std::queue<std::pair<valueType, valueType>> Q;

        for (valueType i = 0; i < CharSetSize; ++i)
            if (Transfer[0][i])
                Q.emplace(0, i);

        while (!Q.empty()) {
            auto [Last, ch] = Q.front();

            Q.pop();

            valueType New = expand(Last, ch);

            for (valueType i = 0; i < CharSetSize; ++i)
                if (Transfer[New][i])
                    Q.emplace(New, i);
        }
    }

    long long Ans() const {
        long long ans = 0;

        for (valueType i = 1; i <= UsedPoolSize; ++i)
            ans += Length[i] - Length[Link[i]];

        return ans;
    }

    valueType size() const {
        return UsedPoolSize + 1;
    }
};

constexpr valueType MAXN = 1e6 + 5;

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

    valueType N;

    std::cin >> N;

    GeneralSuffixAutomaton SA(MAXN);

    for (valueType i = 0; i < N; ++i) {
        string s;

        std::cin >> s;

        SA.insert(s);
    }

    SA.build();

    std::cout << SA.Ans() << std::endl << SA.size() << std::endl;

    return 0;
}

诸神眷顾的幻想乡

发现树链上的字符串一定为从某个叶子出发得到的所有字符串中的子串。

因此我们可以将从所有叶子节点出发得到的所有字符串插入广义后缀自动机中,然后求出本质不同子串个数即可。

Code
#include <bits/stdc++.h>

typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::string string;
typedef std::vector<bool> bitset;

class GeneralSuffixAutomaton {
public:
    constexpr static valueType CharSetSize = 10;
    typedef std::array<valueType, CharSetSize> TransferMap;
    typedef std::vector<TransferMap> TransferMatrix;

private:
    valueType N, UsedPoolSize;
    ValueVector Link, Length;
    TransferMatrix Transfer;
    bitset Cloned;

private:
    valueType insertOnTrie(valueType current, valueType ch) {
        if (Transfer[current][ch])
            return Transfer[current][ch];
        else
            return Transfer[current][ch] = ++UsedPoolSize;
    }

    valueType expand(valueType Last, valueType ch) {
        valueType New = Transfer[Last][ch];

        if (Length[New] != 0)
            return New;

        Length[New] = Length[Last] + 1;

        valueType P = Link[Last];

        while (P != -1 && !Transfer[P][ch]) {
            Transfer[P][ch] = New;

            P = Link[P];
        }

        if (P == -1) {
            Link[New] = 0;
        } else {
            valueType Q = Transfer[P][ch];

            if (Length[P] + 1 == Length[Q]) {
                Link[New] = Q;
            } else {
                valueType Clone = ++UsedPoolSize;

                Length[Clone] = Length[P] + 1;
                Link[Clone] = Link[Q];

                for (valueType i = 0; i < CharSetSize; ++i)
                    Transfer[Clone][i] = Length[Transfer[Q][i]] != 0 ? Transfer[Q][i] : 0;

                Cloned[Clone] = true;

                while (P != -1 && Transfer[P][ch] == Q) {
                    Transfer[P][ch] = Clone;

                    P = Link[P];
                }

                Link[Q] = Link[New] = Clone;
            }
        }

        return New;
    }

public:
    GeneralSuffixAutomaton() = default;

    explicit GeneralSuffixAutomaton(valueType n) : N(n), UsedPoolSize(0), Link(2 * N + 1), Length(2 * N + 1), Transfer(2 * N + 1), Cloned(2 * N + 1, false) {
        Link[0] = -1;

        for (auto &p : Transfer)
            p.fill(0);
    }

    void insert(string const &s) {
        valueType current = 0;

        for (auto ch : s)
            current = insertOnTrie(current, ch - 'a');
    }

    void insert(ValueVector const &s) {
        valueType current = 0;

        for (auto ch : s)
            current = insertOnTrie(current, ch);
    }

    void build() {
        std::queue<std::pair<valueType, valueType>> Q;

        for (valueType i = 0; i < CharSetSize; ++i)
            if (Transfer[0][i])
                Q.emplace(0, i);

        while (!Q.empty()) {
            auto [Last, ch] = Q.front();

            Q.pop();

            valueType New = expand(Last, ch);

            for (valueType i = 0; i < CharSetSize; ++i)
                if (Transfer[New][i])
                    Q.emplace(New, i);
        }
    }

    long long Ans() const {
        long long ans = 0;

        for (valueType i = 1; i <= UsedPoolSize; ++i)
            ans += Length[i] - Length[Link[i]];

        return ans;
    }

    valueType size() const {
        return UsedPoolSize + 1;
    }
};

constexpr valueType MAXN = 2e6 + 5;

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

    valueType N, M;

    std::cin >> N >> M;

    GeneralSuffixAutomaton SA(MAXN);

    ValueVector C(N + 1), D(N + 1, 0);
    ValueMatrix G(N + 1);

    for (valueType i = 1; i <= N; ++i)
        std::cin >> C[i];

    for (valueType i = 1; i < N; ++i) {
        valueType u, v;

        std::cin >> u >> v;

        G[u].push_back(v);
        G[v].push_back(u);

        ++D[u];
        ++D[v];
    }

    std::function<void(valueType, valueType, ValueVector &)> dfs = [&](valueType u, valueType from, ValueVector &path) {
        path.push_back(C[u]);

        if (D[u] == 1 && from != -1)
            SA.insert(path);

        for (auto v : G[u]) {
            if (v == from)
                continue;

            dfs(v, u, path);
        }

        path.pop_back();
    };

    ValueVector path;

    for (valueType i = 1; i <= N; ++i)
        if (D[i] == 1)
            dfs(i, -1, path);

    SA.build();

    std::cout << SA.Ans() << std::endl;

    return 0;
}

[CTSC2012] 熟悉的文章

发现答案具有单调性,因此可以二分答案,下面考虑如何判定答案。

判定的主要任务是求出一种划分方式,使得被匹配的长度和最大。不妨设 \(f_i\) 代表文本串前缀 \(s_{1 \dots i}\) 通过某种划分方式被匹配的最大长度。

那么通过枚举上一次划分的位置,我们可以得到状态转移方程:

\[f_i = \max\left\{f_{i - 1}, \max_{j < i - L} \{f_j + i - j\}\right\} \]

上式中 \(L\) 代表判定的答案,同时我们发现上述式子中对 \(j\) 的限制是不完全的,因为我们还需要限制 \(s_{j + 1, i}\) 在模式串中出现。设 \(l_i\) 代表文本串前缀 \(s_{1 \dots i}\) 最长的在模式串中出现的后缀的长度,该值可以通过对模式串建出广义后缀自动机后对文本串进行匹配得出。那么合法的 \(j\) 应该满足 \(j \in \left[i - l_i, i - L\right]\)

由于该区间的左右端点均是单调的,因此可以使用单调队列优化转移。

复杂度为 \(O(n \log n)\),其中 \(n\) 为文本串长度。

Code
#include <bits/stdc++.h>

typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::string string;
typedef std::vector<bool> bitset;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::deque<ValuePair> PairQueue;

template<valueType CharSetSize, valueType BaseChar>
class GeneralSuffixAutomaton {
public:
    typedef std::array<valueType, CharSetSize> TransferMap;
    typedef std::vector<TransferMap> TransferMatrix;

private:
    valueType N, UsedPoolSize;
    ValueVector Link, Length;
    TransferMatrix Transfer;
    bitset Cloned;

private:
    valueType insertOnTrie(valueType current, valueType ch) {
        if (Transfer[current][ch])
            return Transfer[current][ch];
        else
            return Transfer[current][ch] = ++UsedPoolSize;
    }

    valueType expand(valueType Last, valueType ch) {
        valueType New = Transfer[Last][ch];

        if (Length[New] != 0)
            return New;

        Length[New] = Length[Last] + 1;

        valueType P = Link[Last];

        while (P != -1 && !Transfer[P][ch]) {
            Transfer[P][ch] = New;

            P = Link[P];
        }

        if (P == -1) {
            Link[New] = 0;
        } else {
            valueType Q = Transfer[P][ch];

            if (Length[P] + 1 == Length[Q]) {
                Link[New] = Q;
            } else {
                valueType Clone = ++UsedPoolSize;

                Length[Clone] = Length[P] + 1;
                Link[Clone] = Link[Q];

                for (valueType i = 0; i < CharSetSize; ++i)
                    Transfer[Clone][i] = Length[Transfer[Q][i]] != 0 ? Transfer[Q][i] : 0;

                Cloned[Clone] = true;

                while (P != -1 && Transfer[P][ch] == Q) {
                    Transfer[P][ch] = Clone;

                    P = Link[P];
                }

                Link[Q] = Link[New] = Clone;
            }
        }

        return New;
    }

public:
    GeneralSuffixAutomaton() = default;

    explicit GeneralSuffixAutomaton(valueType n) : N(n), UsedPoolSize(0), Link(2 * N + 1), Length(2 * N + 1), Transfer(2 * N + 1), Cloned(2 * N + 1, false) {
        Link[0] = -1;

        for (auto &p : Transfer)
            p.fill(0);
    }

    void insert(string const &s) {
        valueType current = 0;

        for (auto ch : s)
            current = insertOnTrie(current, ch - BaseChar);
    }

    void insert(ValueVector const &s) {
        valueType current = 0;

        for (auto ch : s)
            current = insertOnTrie(current, ch);
    }

    void build() {
        std::queue<std::pair<valueType, valueType>> Q;

        for (valueType i = 0; i < CharSetSize; ++i)
            if (Transfer[0][i])
                Q.emplace(0, i);

        while (!Q.empty()) {
            auto [Last, ch] = Q.front();

            Q.pop();

            valueType New = expand(Last, ch);

            for (valueType i = 0; i < CharSetSize; ++i)
                if (Transfer[New][i])
                    Q.emplace(New, i);
        }
    }

public:
    // extra functions
    long long GetSubStringCount() const {
        long long ans = 0;

        for (valueType i = 1; i <= UsedPoolSize; ++i)
            ans += Length[i] - Length[Link[i]];

        return ans;
    }

    valueType size() const {
        return UsedPoolSize + 1;
    }

    ValueVector Match(ValueVector const &S, valueType start) const {
        valueType current = 0, len = 0;

        ValueVector ans(S.size(), 0);

        while (start < S.size()) {
            valueType const ch = S[start];

            if (Transfer[current][ch]) {
                current = Transfer[current][ch];
                ++len;
            } else {
                while (current != -1 && !Transfer[current][ch])
                    current = Link[current];

                if (current == -1) {
                    current = len = 0;
                } else {
                    len = Length[current] + 1;
                    current = Transfer[current][ch];
                }
            }

            ans[start] = len;

            ++start;
        }

        return ans;
    }

    ValueVector Match(string const &S, valueType start) const {
        valueType current = 0, len = 0;

        ValueVector ans(S.size(), 0);

        while (start < S.size()) {
            valueType const ch = S[start] - BaseChar;

            if (Transfer[current][ch]) {
                current = Transfer[current][ch];
                ++len;
            } else {
                while (current != -1 && !Transfer[current][ch])
                    current = Link[current];

                if (current == -1) {
                    current = len = 0;
                } else {
                    len = Length[current] + 1;
                    current = Transfer[current][ch];
                }
            }

            ans[start] = len;

            ++start;
        }

        return ans;
    }
};

constexpr valueType MAXN = 1e6 + 1e5 + 5;

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

    valueType T, M;

    std::cin >> T >> M;

    GeneralSuffixAutomaton<2, '0'> SA(MAXN);

    for (valueType i = 0; i < M; ++i) {
        string s;

        std::cin >> s;

        SA.insert(s);
    }

    SA.build();

    for (valueType testcase = 0; testcase < T; ++testcase) {
        string S;

        std::cin >> S;

        valueType const N = S.size();

        auto length = SA.Match(S, 0);

        length.insert(length.begin(), 0);

        auto check = [&](valueType Limit) -> bool {
            ValueVector F(N + 1, 0);

            F[0] = 0;

            PairQueue Q;

            for (valueType i = 1; i <= N; ++i) {
                F[i] = F[i - 1];

                if (i >= Limit) {
                    ValuePair next(F[i - Limit] - (i - Limit), i - Limit);

                    while (!Q.empty() && Q.back().first <= next.first)
                        Q.pop_back();

                    Q.push_back(next);
                }

                while (!Q.empty() && Q.front().second < i - length[i])
                    Q.pop_front();

                if (!Q.empty())
                    F[i] = std::max(F[i], Q.front().first + i);
            }

            return F[N] * 10 >= N * 9;
        };

        valueType L = 0, R = N, ans = 0;

        while (L <= R) {
            valueType const mid = (L + R) / 2;

            if (check(mid)) {
                ans = mid;

                L = mid + 1;
            } else {
                R = mid - 1;
            }
        }

        std::cout << ans << '\n';
    }

    std::cout << std::flush;

    return 0;
}

标签:std,ch,2023.12,valueType,28,Set,Link,Transfer,New
From: https://www.cnblogs.com/User-Unauthorized/p/2023-12-28.html

相关文章

  • JAVA学习12-28 数据类型
    数据类型学习publicclassDemo01{publicstaticvoidmain(String[]args){//单行注释/*多行注释*//*不能用关键字来做标识符*//*标识符可以大写字母,小写字母,美元符号,下划线_开头,不能以关键字作为变量名或方法名,-......
  • .NET 6 控制台程序(Console)读取配置appsettings.json配置文件
    ​ 1、添加引用Microsoft.Extensions.Configuration.Json添加引用 Microsoft.Extensions.Configuration.Json,引用方法可以参考:1)使用Nuget界面管理器搜索"Microsoft.Extensions.Configuration.Json"在列表中分别找到它,点击"安装"相关文档:VS(VisualStudio)中Nuget的使用......
  • 12.28每日总结
    redis测试:redisTestimportjava.util.Map;importredis.clients.jedis.Jedis;publicclassredisTest{/***@paramargs*/publicstaticJedisjedis;publicstaticvoidmain(String[]args){//TODOAuto-generatedmethodstubj......
  • 12.28数组遍历以及动态初始化,数组求最值,基础方法1
    fori用法:数组名.fori直接依次遍历数组中所有元素数组的动态初始化:定义没有元素的数组(静态初始化即已知元素)   方法调用:方法名(); ......
  • set集合&&hashMap总结
    总结实现set接口的集合set集合:无序不重复不重复(去重):元素放入集合之前或做判断无序:存取不一致1、讲解set的实现类HashSet:底层使用哈希表来实现(底层是一个数组,数组里面保存一个单向链表)的集合不允许元素重复,元素是无序的HashSet的去重机制(怎么去除重复)第一步:将要添加到H......
  • [Software Note ] Fibersim-export-OffsetedMesh
    输出Offseted的Drapedata只在fibersim导出界面打开Allowoffsetsimulation选项,输出的网格还是在layupsurface上;同时在ply–simulation–options-中打开offsetmode,输出了偏置后的网格.......
  • flink中的setStreamTimeCharacteristic 指定为EventTime的source需要自己定义event ti
    flink中的setStreamTimeCharacteristicTimeCharacteristic   env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) 此处可以取以下三类值:EventTime事件时间,事件(Event)本身的时间,即数据流中事件实际发生的时间,通常使用事件发生时的时间戳来描述,这些......
  • 12.28每日总结2
    今天下午接着写软件企业文化的大作业市场推广 确定目标市场:首先,你需要确定你的目标市场是谁。考虑该技术最适合哪些行业或领域,并了解这些市场的需求和痛点。深入了解竞争环境:研究类似的软件技术是否已经存在,了解竞争对手的优势和劣势。这有助于你们找到与众不同的竞争优势,并确......
  • 全志R128 DSP开发工具安装教程
    资料准备要编译和仿真DSP,需要以下资料:DSP核SDK,SDK需要包含DSP编译源码。CadenceXtensa的WindowsIDE工具(Xplorer‑8.0.13版本),Windows版本DSP的package包。CadenceXtensa的License,用于服务器代码编译和Xplorer仿真使用。其中Allwinner提供DSP核SDK源码......
  • stm32u5 qspi 读写 w25q128 timeout
    http://ramlife.me/posts/solution/embedded/spi/stm32-use-qspi-write-and-read-w25q128-timeout/背景使用STM32U575主控芯片,使用QSPI读写W25Q128,简单的读写测试没有问题。但是在后面调试中发现,当按照11个字节一组进行读写,从4352这个地址开始写,写入到4605的时候,就超......