Submission #74402767


Source Code Expand

//utf-8

#include <string>
#include <type_traits>
#include <iterator>
#include <cstdint>
#include <vector>
#include <array>
#include <algorithm>
#include <limits>
#include <cassert>
#include <numeric>

#include <vector>
#include <cstdint>
#include <algorithm>
#include <vector>
#include <cstdint>
#include <algorithm>

namespace rmq {

    using std::vector;
    using size_t = std::uint32_t;

    enum rmq_type { rmq_min, rmq_max };

    template <typename value_t, rmq_type type_>
        struct rm { };

    template <typename value_t>
        struct rm <value_t, rmq_min> {
            inline value_t operator () (const value_t &a, const value_t &b) const {
                return std::min(a, b);
            }
        };

    template <typename value_t>
        struct rm <value_t, rmq_max> {
            inline value_t operator () (const value_t &a, const value_t &b) const {
                return std::max(a, b);
            }
        };

    template <typename value_t, rmq_type type_>
        struct rmq_solver {
            typedef value_t value_type;
            static constexpr rmq_type type = type_;
            static rm<value_t, type_> mrg;
            vector<vector<value_t> > st;

            template <typename cont>
                void build(const cont &c){
                    size_t n = c.size();
                    st.resize(std::__lg(n) + 1);
                    st[0].resize(n);
                    std::copy_n(c.begin(), n, st[0].begin());
                    for (size_t i = 1, _ = std::__lg(n); i <= _; ++i){
                        size_t l = n - (1 << i) + 1;
                        st[i].resize(l);
                        const vector<value_t> &pr = st[i - 1];
                        typedef typename vector<value_t>::const_iterator iter;
                        iter _0 = pr.begin(), _1 = _0 + (1 << (i - 1));
                        for (size_t j = 0; j < l; ++j)
                            st[i][j] = mrg(_0[j], _1[j]);
                    }
                }

            inline value_t get(size_t l, size_t r) const {
                size_t t = std::__lg(r - l);
                return mrg(st[t][l], st[t][r - (1 << t)]);
            }

        };

    template <typename value_t, rmq_type type_>
        rm<value_t, type_> rmq_solver<value_t, type_>::mrg{};

}

namespace string_algo {

    using std::basic_string;
    using std::vector;
    using std::array;
    using size_t = std::uint32_t;

    template <typename iter_t, typename iter_tag>
        using ass_iter_tag = std::enable_if<std::is_base_of<iter_tag, typename std::iterator_traits<iter_t>::iterator_category>::value >;
    template <typename iter_t>
        using ass_RAI = ass_iter_tag<iter_t, std::random_access_iterator_tag>;
    #define ass_is_RAI(iter_t) typename = typename ass_RAI<iter_t>::type

    // 前缀函数
    template <typename value_t, typename output_iter_t, ass_is_RAI(output_iter_t)>
        void prefix_function(const basic_string<value_t> &s, output_iter_t pi){//[0,pi_i)=[i-pi_i,i)
            if (s.empty())return;
            size_t n = s.size();
            *pi = 0;
            for (size_t i = 1, j = 0; i != n; ++i){
                while (j && s[i] != s[j])j = pi[j - 1];
                if (s[i] == s[j])++j;
                pi[i] = j;
            }
        }
    // KMP 算法
    template <typename value_t, typename output_iter_t, ass_is_RAI(output_iter_t)>
        vector<size_t> kmp(const basic_string<value_t> &text, const basic_string<value_t> &pat, output_iter_t pi){//返回匹配位置(l point)
            if (text.size() < pat.size())return {};
            if (text.size() == pat.size()){if (text == pat)return {0};return {};}
            if (pat.empty())return {};
            prefix_function(pat, pi);
            size_t n = text.size(), m = pat.size();
            vector<size_t> ret;
            for (size_t i = 0, j = 0; i != n; ++i){
                while (j && text[i] != pat[j])j = pi[j - 1];
                if (text[i] == pat[j])++j;//[i-m+1,i]=[0,j)
                if (j == m)ret.emplace_back(i - m + 1), j = pi[j - 1];
            }
            return ret;
        }

    // z 函数
    template <typename value_t, typename output_iter_t, ass_is_RAI(output_iter_t)>
        void z_function(const basic_string<value_t> &s, output_iter_t z){//z_i = lcp(s,s[i:])
            if (s.empty())return;
            size_t n = s.size();
            *z = n;
            for (size_t i = 1, l = 0, r = 1; i != n; ++i){//[l,r)
                if (i < r && z[i - l] < r - i)z[i] = z[i - l];
                else {
                    if (i < r)z[i] = r - i; else z[i] = 0;
                    while (i + z[i] < n && s[z[i]] == s[i + z[i]])++z[i];
                }
                if (i + z[i] > r)l = i, r = i + z[i];
            }
        }

    // 回文自动机
    template <size_t _val_max>
        struct pam {
            static constexpr size_t value_max = _val_max;// 字符集为 [0,value_max) 内的整数
            basic_string <size_t> str;
            struct node { // 每个结点表示字符串中一个不同的回文子串,在第一次出现时生成
                size_t father; // 前驱
                array<size_t, value_max> children; // 后继
                size_t length; // 当前结点代表字符串的长度
                size_t fail; // 指向最长回文 border
                size_t count; // 以当前节点对应位置结束的回文子串数量
                size_t total; // 当前节点对应子串出现次数
                size_t endpos; // [endpos - length, endpos)
                node(size_t _len = 0) : father{}, children{}, length{_len}, fail{}, count{}, total{}, endpos{} {}
            };
            vector<node> tree;
            size_t last;
            pam() : str{}, tree{}, last{1} {
                tree.reserve(2);
                tree.emplace_back();// 偶根
                tree.emplace_back(-1);// 奇根
                tree[0].fail = 1;
            }
            void clear(){
                str.clear();
                tree.clear();
                tree.reserve(2);
                tree.emplace_back();// 偶根
                tree.emplace_back(-1);// 奇根
                tree[0].fail = 1;
                last = 1;
            }
            size_t _get_fail(size_t now){
                const size_t length = str.size();
                while (length < tree[now].length + 2 || str[length - tree[now].length - 2] != str.back())
                    now = tree[now].fail;
                return now;
            }
            size_t push_back(size_t ch){// 返回 以当前节点对应位置结束的回文子串数量
                str.push_back(ch);
                size_t now = _get_fail(last);
                if (!tree[now].children[ch]){
                    tree.emplace_back(tree[now].length + 2);
                    tree.back().father = now;
                    tree.back().fail = tree[_get_fail(tree[now].fail)].children[ch];
                    tree.back().count = tree[tree.back().fail].count + 1;
                    tree.back().endpos = str.size();
                    tree[now].children[ch] = tree.size() - 1;
                }
                last = tree[now].children[ch];
                ++tree[last].total;
                return tree[last].count;
            }
            void build_total(){
                for (size_t i = tree.size() - 1; i > 1; --i)
                    tree[tree[i].fail].total += tree[i].total;
            }
            size_t init_node(size_t str_length){
                return str_length & 1;
            }
            size_t next(size_t now, size_t ch){
                return tree[now].children[ch];
            }
            bool is_psubstr_of(const basic_string <size_t> &t){// 判断是否为回文子串
                size_t nw = init_node(t.size()), l = (t.size() - 1) >> 1, r = t.size() - 1 - l;
                while (~l){
                    if (t[l] != t[r])return false;
                    nw = next(nw, t[l]), --l, ++r;
                    if (!nw)return false;
                }
                return true;
            }
            template <typename func_t>// 遍历所有非空回文子串
                void for_each_psubstr(func_t func){
                    for (size_t i = 2, _ = tree.size(); i != _; ++i)
                        func(tree[i].endpos - tree[i].length, tree[i].endpos, tree[i].count, tree[i].total);// [left,right), count, total
                }
        };

    // 后缀排序
    template <typename value_t, typename output_iter_t, ass_is_RAI(output_iter_t)>
        void suffix_sort(const basic_string<value_t> &s, output_iter_t sa,
                std::enable_if_t<std::is_unsigned<value_t>::value>* = nullptr){// 返回的 sa_i 在 [0,n) 中
            if (s.empty())return;
            size_t n = s.size();
            size_t *nrk, *c, *id = new size_t [n];
            size_t m;
            {
                size_t maxv = *max_element(s.begin(), s.end());
                if (maxv >= n << 2){
                    c = new size_t [m = n << 1] {};
                    nrk = new size_t [m] {};
                    auto __pred = [&s](size_t u, size_t v){ return s[u] < s[v]; };
                    std::iota(sa, sa + n, 0);
                    std::sort(sa, sa + n, __pred);
                    for (size_t i = 0; i < n; ++i)nrk[i] = std::lower_bound(sa, sa + n, i, __pred) - sa;
                } else {
                    c = new size_t [m = std::max(maxv + 1, n << 1)] {};
                    nrk = new size_t [m] {};
                    std::copy_n(s.begin(), n, nrk);
                    for (size_t i = 0; i < n; ++i)++c[nrk[i]];
                    for (size_t i = 1; i <= maxv; ++i)c[i] += c[i - 1];
                    for (size_t i = n - 1; ~i; --i)sa[--c[nrk[i]]] = i;
                }
            }
            for (size_t i = 0, l = 1; l <= n && m != n; ++i, l <<= 1){
                {
                    size_t t = 0;
                    for (size_t j = n - l; j < n; ++j)id[t++] = j;
                    for (size_t j = 0; j < n; ++j)if (sa[j] >= l)id[t++] = sa[j] - l;
                }
                std::fill_n(c, m, 0);
                for (size_t j = 0; j < n; ++j)++c[nrk[j]];
                for (size_t j = 1; j < m; ++j)c[j] += c[j - 1];
                for (size_t j = n - 1; ~j; --j)sa[--c[nrk[id[j]]]] = id[j];
                std::swap(c, nrk);
                std::fill_n(nrk + n, n, size_t(-1));
                nrk[*sa] = 0;
                for (size_t j = m = 1; j < n; ++j){
                    if (c[sa[j]] != c[sa[j - 1]] || c[sa[j] + l] != c[sa[j - 1] + l])++m;
                    nrk[sa[j]] = m - 1;
                }
            }
            delete []nrk; delete []c; delete []id;
        }
    template <typename value_t, typename output_iter_t, ass_is_RAI(output_iter_t)>
        void suffix_sort(const basic_string<value_t> &s, output_iter_t sa,
                std::enable_if_t<std::is_signed<value_t>::value &&
                    std::is_integral<value_t>::value && std::is_unsigned<
                        typename std::make_unsigned<value_t>::type>::value>* = nullptr){// 返回的 sa_i 在 [0,n) 中
            using U_t = typename std::make_unsigned<value_t>::type;
            basic_string<U_t> ss; ss.resize(s.size());
            std::transform(s.begin(), s.end(), ss.begin(),
                [](value_t x){ return U_t(x) - std::numeric_limits<value_t>::min(); });
            suffix_sort<U_t, output_iter_t>(ss, sa);
        }

    enum class strcmp_t {
        less_no_prefix, // a < b, a not prefix of b
        prefix_of, // a is prefix of b
        same, // a=b
        include, // b is prefix of a
        greater_no_include, // a>b, b not prefix of a
    };

    template <typename value_t>
        struct string_suffix {
            typedef value_t value_type;
            vector<size_t> sa, rk, height; // height_0 = 0   height_i = lcp(sa_i,sa_{i-1})
                // sa_i : suffix id with rank = i
            rmq::rmq_solver<size_t, rmq::rmq_min> rmqs;
            void build(const basic_string<value_t> &s){ // l=1e6, value=char, ~1s
                size_t n = s.size();
                sa.resize(n), rk.resize(n), height.resize(n);
                suffix_sort(s, sa.begin());
                for (size_t i = 0; i < n; ++i)rk[sa[i]] = i;
                height[0] = 0;
                for (size_t i = 0, k = 0; i < n; ++i){
                    if (rk[i] == 0)continue;
                    if (k)--k;
                    size_t mx = std::min(n - i, n - sa[rk[i] - 1]);
                    while (k < mx && s[i + k] == s[sa[rk[i] - 1] + k])++k;
                    height[rk[i]] = k;
                }
                rmqs.build(height);
            }
            string_suffix() = default;
            string_suffix(const basic_string<value_t> &s){ build(s); }
            inline size_t lcp(size_t u, size_t v) const {
                if (u == v)return sa.size() - u;
                u = rk[u], v = rk[v];
                return u > v? rmqs.get(v + 1, u + 1) : rmqs.get(u + 1, v + 1);
            }
            struct substr_t {
                const string_suffix* ss;
                size_t l, r;
                inline strcmp_t cmp_with(const substr_t &o) const {
                    assert(ss == o.ss);
                    size_t lc = ss->lcp(l, o.l);
                    size_t L = r - l, oL = o.r - o.l;
                    if (L == oL && lc >= r - l)return strcmp_t::same;
                    if (L < oL && lc >= L)return strcmp_t::prefix_of;
                    if (L > oL && lc >= oL)return strcmp_t::include;
                    return ss->rk[l + lc] < ss->rk[o.l + lc]? strcmp_t::less_no_prefix : strcmp_t::greater_no_include;
                }
                inline bool operator < (const substr_t &o) const {
                    return cmp_with(o) < strcmp_t::same;
                }
                inline bool operator > (const substr_t &o) const {
                    return cmp_with(o) > strcmp_t::same;
                }
                inline bool operator <= (const substr_t &o) const {
                    return cmp_with(o) <= strcmp_t::same;
                }
                inline bool operator >= (const substr_t &o) const {
                    return cmp_with(o) >= strcmp_t::same;
                }
                inline bool operator == (const substr_t &o) const {
                    return cmp_with(o) == strcmp_t::same;
                }
                inline bool operator != (const substr_t &o) const {
                    return cmp_with(o) != strcmp_t::same;
                }
            };
            substr_t substr(size_t l, size_t r) const { // [l,r)
                return substr_t{this, l, r};
            }
            struct suffix_t {
                const string_suffix* ss;
                size_t p;
                bool operator < (const suffix_t &o) const {
                    assert(ss == o.ss);
                    return ss->rk[p] < ss->rk[o.p];
                }
                bool operator > (const suffix_t &o) const {
                    assert(ss == o.ss);
                    return ss->rk[p] > ss->rk[o.p];
                }
                explicit operator substr_t () const {
                    return substr_t{ss, p, ss->sa.size()};
                }
            };
            suffix_t operator [] (size_t p) const {
                return suffix_t{this, p};
            }
        };

    // 马拉车算法
    template <typename value_t, typename output_iter_t, ass_is_RAI(output_iter_t)>
        void manacher(const basic_string<value_t> &s, output_iter_t even, output_iter_t odd){
            // even_i 为 s_{i-even_i+1} ~ s_{i+even_i} 为回文串的最大值 (0<=i<n-1), odd_i 为 s_{i-odd_i} ~ s_{i+odd_i} 为回文串的最大值 (0<=i<n)
            if (s.empty())return;
            size_t n = s.size();
            if (n == 1){*odd = 0;return;}
            if (s[0] == s[1])*even = 1;else *even = 0;
            for (size_t i = 1, l = 1 - *even, r = *even; i < n - 1; ++i){// [l,r] 为满足 ((l+r-1)/2) < i 且 r 最大的回文子串
                even[i] = l > r || i >= r? (size_t)0 : std::min<size_t>(r - i, even[l + r - i - 1]);
                while (i >= even[i] && i + even[i] + 1 < n && s[i - even[i]] == s[i + even[i] + 1])++even[i];
                if (i + even[i] > r)l = i - even[i] + 1, r = i + even[i];
            }
            *odd = 0;
            for (size_t i = 1, l = 0, r = 0; i < n; ++i){
                odd[i] = i >= r? (size_t)0 : std::min<size_t>(r - i, odd[l + r - i]);
                while (i >= odd[i] + 1 && i + odd[i] + 1 < n && s[i - odd[i] - 1] == s[i + odd[i] + 1])++odd[i];
                if (i + odd[i] > r)l = i - odd[i], r = i + odd[i];
            }
        }

    // 最小表示法
    template <typename iter_t, ass_is_RAI(iter_t)>
        iter_t minimal_string(iter_t bg, iter_t ed){
            if (bg == ed)return bg;
            iter_t i = bg, j = bg + 1;
            while (i != ed && j != ed){
                if (i > j)swap(i, j);
                size_t k = 0;
                while (j + k != ed && *(i + k) == *(j + k))++k;
                if (j + k == ed)break;
                if (*(i + k) < *(j + k))j += k + 1;
                else i += k + 1;
                if (i == j)++j;
            }
            return std::min(i, j);
        }

    // 求最长公共子串
    template <typename value_t>
        size_t longest_common_substr(const basic_string<value_t> &a, const basic_string<value_t> &b){
            string_suffix<value_t> ss(a + b);
            size_t l = 1, r = std::min(a.size(), b.size()), rs = 0;
            while (l <= r){
                size_t M = (l + r) >> 1;
                auto chk = [&](size_t M) -> bool {
                    using substr_t = typename string_suffix<value_t>::substr_t;
                    substr_t pA = ss.substr(0, 0), pB = pA; // empty init
                    const size_t p1 = a.size() - M, p2 = a.size(), p3 = a.size() + b.size() - M;
                    for (size_t i = 0, _ = a.size() + b.size(); i < _; ++i){
                        substr_t sub = ss.substr(ss.sa[i], ss.sa[i] + M);
                        if (ss.sa[i] <= p1){
                            if (sub == pB)return 1;
                            pA = sub;
                        } else if (ss.sa[i] >= p2 && ss.sa[i] <= p3){
                            if (sub == pA)return 1;
                            pB = sub;
                        }
                    }
                    return 0;
                };
                if (chk(M))rs = M, l = M + 1;
                else r = M - 1;
            }
            return rs;
        }

}

#include <bits/stdc++.h>
using namespace std;
int n, a[200010], p, x[200010], q, y[200010];
constexpr int inf = 0x2f2f2f2f;
int main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i)cin >> a[i];
    cin >> p;
    for (int i = 1; i <= p; ++i)cin >> x[i];
    cin >> q;
    for (int i = 1; i <= q; ++i)cin >> y[i];
    auto LCS = [&]{
        // int ret = 0;
        basic_string<int> X(x + 1, x + p + 1), Y(y + 1, y + q + 1);
        return string_algo::longest_common_substr(X, Y);
        // for (int i = 0; i < p; ++i)
        //     for (int j = i; j < p; ++j)if (j - i + 1 > ret)
        //         if (Y.find(X.substr(i, j - i + 1)) != string::npos)ret = j - i + 1;
        // return ret;
    };
    int rs = LCS();
    if (rs > 0){cout << p + q - 2 * rs << endl;return 0;}
    cout << []{
        static int ds[200010];
        memset(ds, 0x2f, sizeof(ds));
        for (int i = 1; i <= p; ++i)ds[x[i]] = 0;
        static vector<int> e[200010];
        for (int i = 1; i < n; ++i)
            e[a[i]].emplace_back(a[i + 1]), e[a[i + 1]].emplace_back(a[i]);
        queue<int> Q;
        for (int i = 1; i <= n; ++i)if (ds[i] == 0)Q.emplace(i);
        while (!Q.empty()){
            int u = Q.front(); Q.pop();
            for (int v : e[u])if (ds[v] > ds[u] + 1)
                ds[v] = ds[u] + 1, Q.emplace(v);
        }
        int rs = inf;
        for (int i = 1; i <= q; ++i)rs = min(rs, ds[y[i]]);
        return rs;
    }() * 2 + p - 1 + q - 1 << endl;
    return 0;
}

Submission Info

Submission Time
Task E - Keep Being Substring
User szt100309
Language C++23 (GCC 15.2.0)
Score 700
Code Size 20728 Byte
Status AC
Exec Time 257 ms
Memory 41100 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 700 / 700
Status
AC × 2
AC × 62
Set Name Test Cases
Sample example0.txt, example1.txt
All 000.txt, 001.txt, 002.txt, 003.txt, 004.txt, 005.txt, 006.txt, 007.txt, 008.txt, 009.txt, 010.txt, 011.txt, 012.txt, 013.txt, 014.txt, 015.txt, 016.txt, 017.txt, 018.txt, 019.txt, 020.txt, 021.txt, 022.txt, 023.txt, 024.txt, 025.txt, 026.txt, 027.txt, 028.txt, 029.txt, 030.txt, 031.txt, 032.txt, 033.txt, 034.txt, 035.txt, 036.txt, 037.txt, 038.txt, 039.txt, 040.txt, 041.txt, 042.txt, 043.txt, 044.txt, 045.txt, 046.txt, 047.txt, 048.txt, 049.txt, 050.txt, 051.txt, 052.txt, 053.txt, 054.txt, 055.txt, 056.txt, 057.txt, 058.txt, 059.txt, example0.txt, example1.txt
Case Name Status Exec Time Memory
000.txt AC 1 ms 3732 KiB
001.txt AC 257 ms 41100 KiB
002.txt AC 13 ms 5340 KiB
003.txt AC 139 ms 26400 KiB
004.txt AC 27 ms 8244 KiB
005.txt AC 43 ms 21364 KiB
006.txt AC 97 ms 21824 KiB
007.txt AC 96 ms 21764 KiB
008.txt AC 97 ms 21832 KiB
009.txt AC 97 ms 21696 KiB
010.txt AC 96 ms 21860 KiB
011.txt AC 118 ms 21816 KiB
012.txt AC 111 ms 21856 KiB
013.txt AC 107 ms 21696 KiB
014.txt AC 111 ms 21832 KiB
015.txt AC 112 ms 21820 KiB
016.txt AC 58 ms 21764 KiB
017.txt AC 55 ms 21696 KiB
018.txt AC 58 ms 21828 KiB
019.txt AC 34 ms 16092 KiB
020.txt AC 32 ms 16024 KiB
021.txt AC 31 ms 16164 KiB
022.txt AC 29 ms 16104 KiB
023.txt AC 29 ms 16176 KiB
024.txt AC 30 ms 16092 KiB
025.txt AC 29 ms 16188 KiB
026.txt AC 9 ms 7800 KiB
027.txt AC 9 ms 7780 KiB
028.txt AC 9 ms 7888 KiB
029.txt AC 14 ms 11648 KiB
030.txt AC 14 ms 11752 KiB
031.txt AC 14 ms 11640 KiB
032.txt AC 8 ms 6744 KiB
033.txt AC 1 ms 3760 KiB
034.txt AC 32 ms 9536 KiB
035.txt AC 3 ms 4100 KiB
036.txt AC 35 ms 9828 KiB
037.txt AC 28 ms 8844 KiB
038.txt AC 66 ms 17040 KiB
039.txt AC 18 ms 6812 KiB
040.txt AC 34 ms 9696 KiB
041.txt AC 25 ms 7924 KiB
042.txt AC 27 ms 8416 KiB
043.txt AC 29 ms 14232 KiB
044.txt AC 20 ms 9560 KiB
045.txt AC 17 ms 8752 KiB
046.txt AC 14 ms 8484 KiB
047.txt AC 12 ms 7900 KiB
048.txt AC 12 ms 8168 KiB
049.txt AC 11 ms 7740 KiB
050.txt AC 11 ms 8100 KiB
051.txt AC 11 ms 8136 KiB
052.txt AC 11 ms 7284 KiB
053.txt AC 11 ms 7388 KiB
054.txt AC 10 ms 7924 KiB
055.txt AC 10 ms 7672 KiB
056.txt AC 9 ms 7284 KiB
057.txt AC 9 ms 6940 KiB
058.txt AC 167 ms 31260 KiB
059.txt AC 47 ms 18028 KiB
example0.txt AC 1 ms 3564 KiB
example1.txt AC 1 ms 3676 KiB