#include using namespace std; #define all(v) (v).begin(),(v).end() #define pb emplace_back #define rep(i, n) for(int i=0;i<(n);i++) #define foa(e, v) for(auto& e : v) #define dout(a) cout< using pqr = priority_queue, greater>; template inline bool chmax(T1 &a, T2 b) { bool compare = a < b; if(compare) a = b; return compare; } template inline bool chmin(T1 &a, T2 b) { bool compare = a > b; if(compare) a = b; return compare; } template inline T back(std::set &s) { return *s.rbegin(); } template inline T back(std::multiset &s) { return *s.rbegin(); } template inline T pop_back(std::set &s) { auto it = prev(s.end()); T val = *it; s.erase(it); return val; } template inline T pop_back(std::multiset &s) { auto it = prev(s.end()); T val = *it; s.erase(it); return val; } const int dy[8] = {-1, 0, 0, 1, 1, -1, 1, -1}; const int dx[8] = {0, -1, 1, 0, -1, -1, 1, 1}; const ll MOD7 = 1000000007, MOD998 = 998244353, INF = (3LL << 59); const int inf = 1 << 30; const char br = '\n'; template struct TrieNode { int nxt[char_size]; int exist; vector accept; TrieNode() : exist(0) { memset(nxt, -1, sizeof(nxt)); } }; template struct Trie { using Node = TrieNode; vector nodes; int root; Trie() : root(0) { nodes.push_back(Node()); } void add(const string& str, int str_index, int node_index, int id) { if(str_index == size(str)) { nodes[node_index].accept.push_back(id); } else { const int c = str[str_index] - margin; if(nodes[node_index].nxt[c] == -1) { nodes[node_index].nxt[c] = size(nodes); nodes.push_back(Node()); } add(str, str_index + 1, nodes[node_index].nxt[c], id); nodes[node_index].exist ++; } } void add(const string& str, int id = -1) { if(id == -1) id = nodes[0].exist; add(str, 0, 0, id); } }; template struct AhoCorasick : Trie { using Trie::Trie; const int FAIL = char_size; vector correct; void build(bool heavy = true) { correct.resize(this->nodes.size()); for(int i = 0; i < size(this->nodes); ++i) { correct[i] = size(this->nodes[i].accept); } queue que; for(int i = 0; i < char_size; ++i) { if(~this->nodes[0].nxt[i]) { this->nodes[this->nodes[0].nxt[i]].nxt[FAIL] = 0; que.emplace(this->nodes[0].nxt[i]); } else { this->nodes[0].nxt[i] = 0; } } while(!que.empty()) { auto& now = this->nodes[que.front()]; int fail = now.nxt[FAIL]; correct[que.front()] += correct[fail]; que.pop(); for(int i = 0; i < char_size; i++) { if(~now.nxt[i]) { this->nodes[now.nxt[i]].nxt[FAIL] = this->nodes[fail].nxt[i]; if(heavy) { auto& u = this->nodes[now.nxt[i]].accept; auto& v = this->nodes[this->nodes[fail].nxt[i]].accept; vector accept; set_union(all(u), all(v), back_inserter(accept)); u = accept; } que.emplace(now.nxt[i]); } else { now.nxt[i] = this->nodes[fail].nxt[i]; } } } } vector match(const char& c, int now = 0) { vector res; now = this->nodes[now].nxt[c - margin]; for(auto& v : this->nodes[now].accept) res.push_back(v); return res; } unordered_map match(const string& str, int now = 0) { unordered_map res, visit_cnt; for(auto& c : str) { now = this->nodes[now].nxt[c - margin]; visit_cnt[now]++; } for(auto& [now, cnt] : visit_cnt) { for(auto& v : this->nodes[now].accept) res[v] += cnt; } return res; } pair move(const char& c, int now = 0) { now = this->nodes[now].nxt[c - margin]; return {correct[now], now}; } }; void solve() { string S; cin >> S; int M; cin >> M; AhoCorasick<26, 'A'> aho; for(int i = 0; i < M; i++) { string s; cin >> s; aho.add(s); } aho.build(); ll sum = 0; int now = 0; foa(e, S) { auto [cnt, nx] = aho.move(e, now); sum += cnt; now = nx; } cout << sum << endl; } int main() { cin.tie(0); ios::sync_with_stdio(false); int testcase = 1; // cin >> testcase; while(testcase --) solve(); return 0; }