#include using namespace std; using lint = long long; using pint = pair; using plint = pair; 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##_begin_;i--) #define REP(i, n) FOR(i,0,n) #define IREP(i, n) IFOR(i,0,n) template void ndarray(vector& vec, const V& val, int len) { vec.assign(len, val); } template void ndarray(vector& vec, const V& val, int len, Args... args) { vec.resize(len), for_each(begin(vec), end(vec), [&](T& v) { ndarray(v, val, args...); }); } template bool chmax(T &m, const T q) { if (m < q) {m = q; return true;} else return false; } template 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 pair operator+(const pair &l, const pair &r) { return make_pair(l.first + r.first, l.second + r.second); } template pair operator-(const pair &l, const pair &r) { return make_pair(l.first - r.first, l.second - r.second); } template vector sort_unique(vector vec) { sort(vec.begin(), vec.end()), vec.erase(unique(vec.begin(), vec.end()), vec.end()); return vec; } template istream &operator>>(istream &is, vector &vec) { for (auto &v : vec) is >> v; return is; } template ostream &operator<<(ostream &os, const vector &vec) { os << '['; for (auto v : vec) os << v << ','; os << ']'; return os; } template ostream &operator<<(ostream &os, const array &arr) { os << '['; for (auto v : arr) os << v << ','; os << ']'; return os; } #if __cplusplus >= 201703L template istream &operator>>(istream &is, tuple &tpl) { std::apply([&is](auto &&... args) { ((is >> args), ...);}, tpl); return is; } template ostream &operator<<(ostream &os, const tuple &tpl) { std::apply([&os](auto &&... args) { ((os << args << ','), ...);}, tpl); return os; } #endif template ostream &operator<<(ostream &os, const deque &vec) { os << "deq["; for (auto v : vec) os << v << ','; os << ']'; return os; } template ostream &operator<<(ostream &os, const set &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template ostream &operator<<(ostream &os, const unordered_set &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template ostream &operator<<(ostream &os, const multiset &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template ostream &operator<<(ostream &os, const unordered_multiset &vec) { os << '{'; for (auto v : vec) os << v << ','; os << '}'; return os; } template ostream &operator<<(ostream &os, const pair &pa) { os << '(' << pa.first << ',' << pa.second << ')'; return os; } template ostream &operator<<(ostream &os, const map &mp) { os << '{'; for (auto v : mp) os << v.first << "=>" << v.second << ','; os << '}'; return os; } template ostream &operator<<(ostream &os, const unordered_map &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: template struct light_forward_list { static std::vector ptr; static std::vector 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 std::vector light_forward_list::ptr = {0}; template std::vector light_forward_list::val = {0}; // Aho-Corasick algorithm // Verify: // Complexity: // - add(): O(|str_i|) // - build_aho_corasick(): O(\sum_i |str_i|) // - match() : O(\sum_i |str_i| + |str|) template struct AhoCorasick { const int D; std::vector node; AhoCorasick(int D_) : D(D_), node(1, D) {} std::vector 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 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 match(const std::string &str) { std::vector 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 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 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 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 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 trie(62); trie.add(P); trie.build_aho_corasick(); vector ret = trie.match(); */ int main() { string S, C; int M; cin >> S >> M; AhoCorasick 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'; }