結果
問題 | No.430 文字列検索 |
ユーザー | hitonanode |
提出日時 | 2020-12-31 18:49:23 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 12 ms / 2,000 ms |
コード長 | 8,601 bytes |
コンパイル時間 | 2,122 ms |
コンパイル使用メモリ | 215,564 KB |
実行使用メモリ | 5,248 KB |
最終ジャッジ日時 | 2024-11-10 00:51:26 |
合計ジャッジ時間 | 2,642 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 12 ms
5,248 KB |
testcase_02 | AC | 6 ms
5,248 KB |
testcase_03 | AC | 6 ms
5,248 KB |
testcase_04 | AC | 2 ms
5,248 KB |
testcase_05 | AC | 1 ms
5,248 KB |
testcase_06 | AC | 1 ms
5,248 KB |
testcase_07 | AC | 1 ms
5,248 KB |
testcase_08 | AC | 2 ms
5,248 KB |
testcase_09 | AC | 2 ms
5,248 KB |
testcase_10 | AC | 2 ms
5,248 KB |
testcase_11 | AC | 6 ms
5,248 KB |
testcase_12 | AC | 6 ms
5,248 KB |
testcase_13 | AC | 6 ms
5,248 KB |
testcase_14 | AC | 5 ms
5,248 KB |
testcase_15 | AC | 5 ms
5,248 KB |
testcase_16 | AC | 4 ms
5,248 KB |
testcase_17 | AC | 4 ms
5,248 KB |
ソースコード
#include <bits/stdc++.h> using namespace std; using lint = long long; using pint = pair<int, int>; using plint = pair<lint, lint>; struct fast_ios { fast_ios(){ cin.tie(nullptr), ios::sync_with_stdio(false), cout << fixed << setprecision(20); }; } fast_ios_; #define ALL(x) (x).begin(), (x).end() #define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++) #define IFOR(i, begin, end) for(int i=(end)-1,i##_begin_=(begin);i>=i##_begin_;i--) #define REP(i, n) FOR(i,0,n) #define IREP(i, n) IFOR(i,0,n) template <typename T, typename V> void ndarray(vector<T>& vec, const V& val, int len) { vec.assign(len, val); } template <typename T, typename V, typename... Args> void ndarray(vector<T>& vec, const V& val, int len, Args... args) { vec.resize(len), for_each(begin(vec), end(vec), [&](T& v) { ndarray(v, val, args...); }); } template <typename T> bool chmax(T &m, const T q) { if (m < q) {m = q; return true;} else return false; } template <typename T> bool chmin(T &m, const T q) { if (m > q) {m = q; return true;} else return false; } int floor_lg(long long x) { return x <= 0 ? -1 : 63 - __builtin_clzll(x); } template <typename T1, typename T2> pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first + r.first, l.second + r.second); } template <typename T1, typename T2> pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) { return make_pair(l.first - r.first, l.second - r.second); } template <typename T> vector<T> sort_unique(vector<T> vec) { sort(vec.begin(), vec.end()), vec.erase(unique(vec.begin(), vec.end()), vec.end()); return vec; } template <typename T> istream &operator>>(istream &is, vector<T> &vec) { for (auto &v : vec) is >> v; return is; } template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) { os << '['; for (auto v : vec) os << v << ','; os << ']'; return os; } template <typename T, size_t sz> ostream &operator<<(ostream &os, const array<T, sz> &arr) { os << '['; for (auto v : arr) os << v << ','; os << ']'; return os; } #if __cplusplus >= 201703L template <typename... T> istream &operator>>(istream &is, tuple<T...> &tpl) { std::apply([&is](auto &&... args) { ((is >> args), ...);}, tpl); return is; } template <typename... T> ostream &operator<<(ostream &os, const tuple<T...> &tpl) { std::apply([&os](auto &&... args) { ((os << args << ','), ...);}, tpl); return os; } #endif template <typename T> ostream &operator<<(ostream &os, const deque<T> &vec) { os << "deq["; for (auto v : vec) os << v << ','; os << ']'; return os; } template <typename T> ostream &operator<<(ostream &os, const set<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template <typename T, typename TH> ostream &operator<<(ostream &os, const unordered_set<T, TH> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template <typename T> ostream &operator<<(ostream &os, const multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template <typename T> ostream &operator<<(ostream &os, const unordered_multiset<T> &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template <typename T1, typename T2> ostream &operator<<(ostream &os, const pair<T1, T2> &pa) { os << '(' << pa.first << ',' << pa.second << ')'; return os; } template <typename TK, typename TV> ostream &operator<<(ostream &os, const map<TK, TV> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; } template <typename TK, typename TV, typename TH> ostream &operator<<(ostream &os, const unordered_map<TK, TV, TH> &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; } #ifdef HITONANODE_LOCAL const string COLOR_RESET = "\033[0m", BRIGHT_GREEN = "\033[1;32m", BRIGHT_RED = "\033[1;31m", BRIGHT_CYAN = "\033[1;36m", NORMAL_CROSSED = "\033[0;9;37m", RED_BACKGROUND = "\033[1;41m", NORMAL_FAINT = "\033[0;2m"; #define dbg(x) cerr << BRIGHT_CYAN << #x << COLOR_RESET << " = " << (x) << NORMAL_FAINT << " (L" << __LINE__ << ") " << __FILE__ << COLOR_RESET << endl #else #define dbg(x) {} #endif // Simple forward_list for MLE-sensitive situations // Verify: <http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_D> template <typename T> struct light_forward_list { static std::vector<unsigned> ptr; static std::vector<T> val; unsigned head; light_forward_list() : head(0) {} void push_front(T x) { ptr.push_back(head), val.push_back(x); head = ptr.size() - 1; } struct iterator { unsigned p; iterator operator++() { return {p = ptr[p]}; } T &operator*() { return val[p]; } bool operator!=(const iterator &rhs) { return p != rhs.p; } }; iterator begin() { return {head}; } iterator end() { return {0}; } }; template <typename T> std::vector<unsigned> light_forward_list<T>::ptr = {0}; template <typename T> std::vector<T> light_forward_list<T>::val = {0}; // Aho-Corasick algorithm // Verify: <http://judge.u-aizu.ac.jp/onlinejudge/review.jsp?rid=5101653> // Complexity: // - add(): O(|str_i|) // - build_aho_corasick(): O(\sum_i |str_i|) // - match() : O(\sum_i |str_i| + |str|) template <class T, int (*char2int)(char)> struct AhoCorasick { const int D; std::vector<T> node; AhoCorasick(int D_) : D(D_), node(1, D) {} std::vector<int> endpos; int add(const std::string &str) { assert(str.length() > 0); int now = 0; for (const auto &c : str) { const int i = char2int(c); if (!get_child(now, i)) { node[now].set(i, node.size()); node.emplace_back(D); } now = get_child(now, i); } return endpos.push_back(now), now; } std::vector<int> visorder; // BFS order of node ids void build_aho_corasick() { visorder.clear(); for (int i = 0; i < D; i++) { int u = get_child(0, i); if (u) visorder.push_back(u); } for (size_t p = 0; p < visorder.size(); p++) { int s = visorder[p]; for (int i = 0; i < D; i++) { const int u = get_child(s, i); if (!u) continue; visorder.push_back(u); int t = node[s].fail, c = get_child(t, i); while (t and !c) t = node[t].fail, c = get_child(t, i); node[u].fail = c; } } } int get_child(int now, int d) { return node[now].child(d); } int step(int now, int d) { while (now and !get_child(now, d)) now = node[now].fail; return get_child(now, d); } // Count occurences of each added strings in `str` std::vector<int> match(const std::string &str) { std::vector<int> freq(node.size()); int now = 0; for (const auto &c : str) freq[now = step(now, char2int(c))]++; for (auto i = visorder.rbegin(); i != visorder.rend(); i++) freq[node[*i].fail] += freq[*i]; std::vector<int> ret; for (auto x : endpos) ret.push_back(freq[x]); return ret; } }; struct TrieNodeFL { static const int B = 8, mask = (1 << B) - 1; light_forward_list<unsigned> chlist; // 下位 B bits が文字種,上位 bit が行き先 unsigned fail; TrieNodeFL(int = 0) : fail(0) {} int child(int d) { for (const auto x : chlist) if ((x & mask) == d) return x >> B; return 0; } void set(int d, unsigned i) { chlist.push_front(d + (i << B)); } }; struct TrieNodeV { std::vector<unsigned> ch; // 全 bit が行き先 unsigned fail; TrieNodeV(int D = 0) : ch(D), fail(0) {} int child(int d) { return ch[d]; } void set(int d, unsigned i) { ch[d] = i; } }; struct TrieNodeUM { std::unordered_map<int, unsigned> mp; unsigned fail; TrieNodeUM(int = 0) : fail(0) {} int child(int d) { return mp.count(d) ? mp[d] : 0; } void set(int d, unsigned i) { mp[d] = i; } }; int c2i0aA(char c) { return isdigit(c) ? c - '0' : islower(c) ? c - 'a' + 10 : c - 'A' + 36; } int c2iA(char c) { return c - 'A'; } /* Usage: AhoCorasick<TrieNodeFL, c2i0aA> trie(62); trie.add(P); trie.build_aho_corasick(); vector<int> ret = trie.match(); */ int main() { string S, C; int M; cin >> S >> M; AhoCorasick<TrieNodeFL, c2iA> trie(26); while (M--) cin >> C, trie.add(C); trie.build_aho_corasick(); auto v = trie.match(S); cout << std::accumulate(v.begin(), v.end(), 0LL) << '\n'; }