結果
問題 | No.430 文字列検索 |
ユーザー | suisen |
提出日時 | 2021-09-08 17:00:24 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 40 ms / 2,000 ms |
コード長 | 5,406 bytes |
コンパイル時間 | 1,137 ms |
コンパイル使用メモリ | 100,552 KB |
実行使用メモリ | 17,024 KB |
最終ジャッジ日時 | 2024-11-10 00:57:26 |
合計ジャッジ時間 | 2,042 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 40 ms
17,016 KB |
testcase_02 | AC | 13 ms
9,860 KB |
testcase_03 | AC | 12 ms
9,864 KB |
testcase_04 | AC | 1 ms
5,248 KB |
testcase_05 | AC | 1 ms
5,248 KB |
testcase_06 | AC | 2 ms
5,248 KB |
testcase_07 | AC | 2 ms
5,248 KB |
testcase_08 | AC | 38 ms
17,024 KB |
testcase_09 | AC | 2 ms
5,248 KB |
testcase_10 | AC | 5 ms
5,248 KB |
testcase_11 | AC | 39 ms
16,656 KB |
testcase_12 | AC | 38 ms
16,912 KB |
testcase_13 | AC | 40 ms
16,912 KB |
testcase_14 | AC | 38 ms
16,656 KB |
testcase_15 | AC | 35 ms
16,780 KB |
testcase_16 | AC | 25 ms
16,440 KB |
testcase_17 | AC | 23 ms
16,204 KB |
ソースコード
#define PROBLEM "https://yukicoder.me/problems/no/430" #include <iostream> #include <cassert> #include <deque> #include <map> #include <string> #include <vector> namespace suisen { /** * reference : https://w.atwiki.jp/uwicoder/pages/2842.html */ template <typename T, typename SequenceType> struct SuffixAutomatonBase { struct Node { std::map<T, int> nxt; int link, len; bool cloned; }; std::vector<Node> nodes; int last; SuffixAutomatonBase() { nodes.push_back({ {}, -1, 0, false }); last = 0; } SuffixAutomatonBase(const SequenceType &s) : SuffixAutomatonBase() { for (const T &c : s) append(c); } void append(const T &c) { const int new_node = nodes.size(); nodes.push_back({ {}, -1, nodes[last].len + 1, false }); int p = last; for (; p != -1 and not nodes[p].nxt.count(c); p = nodes[p].link) nodes[p].nxt[c] = new_node; const int q = p == -1 ? 0 : nodes[p].nxt[c]; if (p == -1 or nodes[p].len + 1 == nodes[q].len) { nodes[new_node].link = q; } else { const int clone_node = nodes.size(); nodes.push_back({ nodes[q].nxt, nodes[q].link, nodes[p].len + 1, true }); for (; p != -1 and nodes[p].nxt[c] == q; p = nodes[p].link) nodes[p].nxt[c] = clone_node; nodes[new_node].link = nodes[q].link = clone_node; } last = new_node; } SuffixAutomatonBase& operator+=(const T &c) { append(c); return *this; } bool accept(const SequenceType &t) const { int cur = 0; for (const auto &c : t) { auto it = nodes[cur].nxt.find(c); if (it == nodes[cur].nxt.end()) return false; cur = it->second; } return true; } class SubstringCounter { public: SubstringCounter(const SuffixAutomatonBase *sa, std::vector<long long> &&dp) : sa(sa), dp(std::move(dp)) {} long long count(const SequenceType &t) const { int cur = 0; for (const auto &c : t) { auto it = sa->nodes[cur].nxt.find(c); if (it == sa->nodes[cur].nxt.end()) return 0; cur = it->second; } return dp[cur]; } private: const SuffixAutomatonBase *sa; const std::vector<long long> dp; }; SubstringCounter substring_counter() const & { const int n = nodes.size(); const std::vector<int> ord = topological_order(); std::vector<long long> dp(n, 0); for (int i = n - 1; i > 0; --i) { const int u = ord[i]; if (not nodes[u].cloned) ++dp[u]; dp[nodes[u].link] += dp[u]; } return SubstringCounter { this, std::move(dp) }; } SubstringCounter substring_counter() const && = delete; // returns { from, len } s.t. lcs = t[from:from+len] std::pair<int, int> longest_common_substring(const SequenceType &t) const { if (t.size() == 0) return { 0, 0 }; const Node *v = &nodes[0]; int l = 0, best = 0, best_pos = 0; for (int i = 0; i < int(t.size()); ++i){ while (v->link != -1 and not v->nxt.count(t[i])) { v = &nodes[v->link]; l = v->len; } auto it = v->nxt.find(t[i]); if (it != v->nxt.end()){ v = &nodes[it->second]; l++; } if (l > best){ best = l; best_pos = i; } } return { best_pos - best + 1, best }; } std::vector<int> topological_order() const { const int n = nodes.size(); std::vector<int> in(n, 0); for (const auto &node : nodes) { for (const auto &p : node.nxt) ++in[p.second]; } std::deque<int> dq; for (int i = 0; i < n; ++i) { if (in[i] == 0) dq.push_back(i); } std::vector<int> res; while (dq.size()) { int u = dq.front(); dq.pop_front(); res.push_back(u); for (const auto &p : nodes[u].nxt) { if (--in[p.second] == 0) dq.push_back(p.second); } } assert(int(res.size()) == n); return res; } }; template <typename T> struct SuffixAutomaton : public SuffixAutomatonBase<T, std::vector<T>> { using SuffixAutomatonBase<T, std::vector<T>>::SuffixAutomatonBase; using value_type = T; using sequence_type = std::vector<T>; }; template <typename T> SuffixAutomaton(std::vector<T>) -> SuffixAutomaton<T>; template <> struct SuffixAutomaton<char> : public SuffixAutomatonBase<char, std::string> { using SuffixAutomatonBase<char, std::string>::SuffixAutomatonBase; using value_type = char; using sequence_type = std::string; }; SuffixAutomaton(std::string) -> SuffixAutomaton<char>; } // namespace suisen using suisen::SuffixAutomaton; int main() { std::string s; std::cin >> s; SuffixAutomaton sa(s); auto counter = sa.substring_counter(); int m; std::cin >> m; long long ans = 0; while (m --> 0) { std::string c; std::cin >> c; ans += counter.count(c); } std::cout << ans << '\n'; return 0; }