#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define rep(n, i) for (int i = 0; i < n; i++) #define rep2(start, end, i) for (int i = start; i < end; i++) #define rep3(start, end, step, i) for (int i = start; i < end; i+=step) #define reprev(n, i) for (int i = n-1; i >= 0; i--) #define reprev2(start, end, i) for (int i = start-1; i >= end; i--) #define reprev3(start, end, step, i) for (int i = start-1; i >= end; i-=step) using namespace std; using namespace atcoder; using ll = long long; using ull = unsigned long long; using mint = modint998244353; template > using ost = __gnu_pbds::tree; void yes() { cout << "Yes" << endl; } void no() { cout << "No" << endl; } void yesno(bool yes) { yes ? ::yes() : no(); } void noyes(bool no) { yesno(!no); } bool inrange(int i, int j, int h, int w) { return 0 <= i && i < h && 0 <= j && j < w; } template T isqrt(T n) { if (n == 0) return 0; T temp = sqrt(n) - 1; return temp * (temp + 2) < n ? temp + 1 : temp; } template T power(T x, int n) { T ret = 1; rep(n, i) { ret *= x; } return ret; } template struct triple { T first; U second; V third; auto operator<=>(const triple&) const = default; }; struct Dir { int i; int j; string word; }; vector dirs1{ {0, 1, "R"}, {1, 0, "D"}, {-1, 0, "U"}, {0, -1, "L"} }; vector dirs2{ {-1, 1, "UR"}, {1, 1, "DR"}, {-1, -1, "UL"}, {1, -1, "DL"}, }; // インデックス i の逆方向が (7 - i) になるように配置した8方向 vector dirs3{ {-1, 0, "U"}, // 0: 上 <---> 7: 下 {-1, 1, "UR"}, // 1: 右上 <---> 6: 左下 { 0, 1, "R"}, // 2: 右 <---> 5: 左 { 1, 1, "DR"}, // 3: 右下 <---> 4: 左上 {-1, -1, "UL"}, // 4: 左上 <---> 3: 右下 { 0, -1, "L"}, // 5: 左 <---> 2: 右 { 1, -1, "DL"}, // 6: 左下 <---> 1: 右上 { 1, 0, "D"} // 7: 下 <---> 0: 上 }; template struct Trie { struct node { T prefix; T term; int nxt[26]; }; vector nodes{node{}}; int get(const string& s) { int cur = 0; for (char c: s) { auto nxt = nodes[cur].nxt[c - 'a']; if (nxt == 0) { return -1; } else { cur = nxt; } } return cur; } void add(const string& s, T x) { int cur = 0; nodes[cur].prefix += x; for (char c: s) { int nxt = nodes[cur].nxt[c - 'a']; if (nxt == 0) { nodes.push_back(node{}); nodes[cur].nxt[c - 'a'] = nodes.size() - 1; } cur = nodes[cur].nxt[c - 'a']; nodes[cur].prefix += x; } nodes[cur].term += x; } }; template struct Lca { int n, l{0}; vector depth; vector> to, par; vector> co; vector costs; Lca(int n): n(n), depth(n), to(n), par(n), co(n), costs(n) { while((1 << l) < n) ++l; par.assign(n+1, vector(l, n)); } void addEdge(int a, int b, T c = 0) { to[a].push_back(b); co[a].push_back(c); to[b].push_back(a); co[b].push_back(c); } void init() { dfs(0, n, 0, 0); for (int i = 0; i < l-1; i++) { for (int u = 0; u < n; u++) { par[u][i+1] = par[par[u][i]][i]; } } } int up(int u, int k) { for (int i = l-1; i >= 0; i--) { int len = 1 << i; if (len <= k) { k -= len; u = par[u][i]; } } return u; } int point(int u, int v) { if (depth[v] < depth[u]) swap(u, v); v = up(v, depth[v] - depth[u]); if (u == v) return u; for (int i = l-1; i >= 0; i--) { if (par[u][i] != par[v][i]) { u = par[u][i]; v = par[v][i]; } } return par[u][0]; } int dist(int u, int v) {return depth[u] + depth[v] - 2 * depth[point(u, v)];} int cost(int u, int v) {return costs[u] + costs[v] - 2 * costs[point(u, v)];} bool onPath(int u, int v, int w) {return dist(u, w) + dist(w, v) == dist(u, v);} private: void dfs(int u, int p, int d, T c) { depth[u] = d; costs[u] = c; par[u][0] = p; for (int i = 0; i < to[u].size(); i++) { if (to[u][i] == p) continue; dfs(to[u][i], u, d+1, c+co[u][i]); } } }; template struct Minplus { T val{}; bool inf = true; Minplus() = default; Minplus(T val): val(val), inf(false) {}; Minplus& operator+=(const Minplus& rhs) { *this = *this + rhs; return *this; } Minplus operator+(const Minplus& rhs) { if (inf) { return rhs; } else if (rhs.inf) { return *this; } else { return Minplus(min(val, rhs.val)); } } Minplus& operator*=(const Minplus& rhs) { *this = *this * rhs; return *this; } Minplus operator*(const Minplus& rhs) { if (inf || rhs.inf) { return Minplus(); } else { return Minplus(val + rhs.val); } } friend ostream& operator<<(ostream& os, const Minplus& rhs) { if (rhs.inf) { os << "inf"; } else { os << rhs.val; } return os; } }; template struct Mulid { static T get() {return T(1);} }; template struct Mulid> { static T get() {return T(0);} }; template struct Mat { int h; int w; vector> data; Mat(int h, int w): h(h), w(w), data(h, vector(w, T{})) {}; Mat(const vector>& data): h(data.size()), w(data[0].size()), data(data) {}; Mat(const initializer_list>& d): h(d.size()), w(d.begin()->size()) { for (auto row: d) { data.emplace_back(row); } }; static Mat e(int n) { Mat ret = Mat(n, n); rep(n, i) { ret.data[i][i] = Mulid::get(); } return ret; } friend ostream& operator<<(ostream& os, const Mat& m) { os << "Mat {" << endl; rep(m.h, i) { rep(m.w, j) { os << m.data[i][j] << ", "; } os << endl; } os << "}"; return os; } Mat& operator*=(const Mat& rhs) { *this = *this * rhs; return *this; } Mat operator*(const Mat& m) { assert(w == m.h); Mat ret(h, m.w); rep(h, i) { rep(m.w, j) { rep(w, k) { ret.data[i][j] += data[i][k] * m.data[k][j]; } } } return ret; } template Mat pow(V n) { assert(h == w); Mat ret = e(h); Mat cur = *this; while (n > 0) { if (n & 1) { ret *= cur; } cur *= cur; n >>= 1; } return ret; } }; template struct Aho { static constexpr int size = end - start + 1; struct node { bool term; int fail; int in; int out; int nxt[size]; int move[size]; }; vector nodes = {node{}}; vector ids; vector cnt; void add(const string& s) { int cur = 0; for (auto c: s) { if (nodes[cur].nxt[c - start] == 0) { nodes.push_back(node{}); nodes[cur].nxt[c - start] = nodes.size() - 1; } cur = nodes[cur].nxt[c - start]; } nodes[cur].term = true; ids.push_back(cur); } void init() { deque que; rep(size, i) { int nxt = nodes[0].nxt[i]; if (nxt != 0) { nodes[0].move[i] = nxt; nodes[0].in++; que.push_back(nxt); } } while (!que.empty()) { int u = que.front(); que.pop_front(); int out = nodes[nodes[u].fail].term ? nodes[u].fail : nodes[nodes[u].fail].out; nodes[u].out = out; nodes[out].in++; rep(size, i) { nodes[u].move[i] = nodes[nodes[u].fail].move[i]; int nxt = nodes[u].nxt[i]; if (nxt != 0) { nodes[u].move[i] = nxt; int fail = nodes[nodes[u].fail].move[i]; nodes[nxt].fail = fail; que.push_back(nxt); } } } } void search(const string& s) { cnt = vector(nodes.size(), 0); int cur = 0; for (auto c: s) { cur = nodes[cur].move[c - start]; cnt[cur]++; } vector que; vector tin(nodes.size()); rep(nodes.size(), i) { tin[i] = nodes[i].in; if (tin[i] == 0) { que.push_back(i); } } while (!que.empty()) { int u = que.back(); que.pop_back(); int nxt = nodes[u].out; cnt[nxt] += cnt[u]; tin[nxt]--; if (tin[nxt] == 0) { que.push_back(nxt); } } } int count(int id) { return cnt[ids[id]]; } }; // ostream& operator<<(ostream&os, const mint m); // template // ostream& operator<<(ostream& os, const pair& p); // template // ostream& operator<<(ostream& os, const tuple& t); // template // ostream& operator<<(ostream& os, const vector& v); // template // ostream& operator<<(ostream& os, const set& s); // template // ostream& operator<<(ostream& os, const map& m); // template // ostream& operator<<(ostream& os, const deque& v); // template > // ostream& operator<<(ostream& os, const ost& ost); // template // ostream& operator<<(ostream& os, const triple& triple); // template // ostream& operator<<(ostream& os, const Mat& Mat); template ostream& operator<<(ostream& os, const ost &t) { os << "ost {"; for (auto it = t.begin(); it != t.end(); ++it) { os << *it; if (next(it) != t.end()) { os << ", "; } } os << "}"; return os; } ostream& operator<<(ostream& os, const mint m) { os << m.val(); return os; } template ostream& operator<<(ostream& os, const pair& p) { os << "(" << p.first << ", " << p.second << ")"; return os; } template ostream& operator<<(ostream& os, const vector& v) { os << "["; rep(v.size(), i) { os << v[i]; if (i != v.size()-1) { os << ", "; } } os << "]"; return os; } template ostream& operator<<(ostream& os, const set& s) { os << "set"; os << vector(s.begin(), s.end()); return os; } template ostream& operator<<(ostream& os, const map& m) { os << "map"; os << vector(m.begin(), m.end()); return os; } template ostream& operator<<(ostream& os, const deque& v) { os << "deque(["; rep(v.size(), i) { os << v[i]; if (i != v.size()-1) { os << ", "; } } os << "])"; return os; } template ostream& operator<<(ostream& os, const triple& triple) { os << "triple{"; os << triple.first << ", " << triple.second << ", " << triple.third << "}"; return os; } vector inv; vector finv; vector fact; void cominit(int n) { inv.assign(n+1, 0); finv.assign(n+1, 0); fact.assign(n+1, 0); inv[1] = 1; finv[0] = 1; finv[1] = 1; fact[0] = 1; fact[1] = 1; rep2(2, n+1, i) { inv[i] = -inv[mint::mod() % i] * (mint::mod() / i); finv[i] = finv[i-1] * inv[i]; fact[i] = fact[i-1] * i; } } mint com(int n, int k) { if (n < 0 || k < 0 || n < k) { return 0; } else { return fact[n] * finv[k] * finv[n-k]; } } template mint com2(T n, int k) { if (n <= 0 || k < 0 || n < k) { return 0; } else { mint ret = 1; rep(k, i) { ret *= n - i; ret /= k - i; } return ret; } } template vector> rle(const Container& con) { using Element = typename Container::value_type; vector> ret; if (con.empty()) return ret; Element cur = con[0]; V cnt{1}; rep2(1, con.size(), i) { if (con[i] == cur) ++cnt; else { ret.push_back({cur, cnt}); cur = con[i]; cnt = 1; } } ret.push_back({cur, cnt}); return ret; } template void outrange(const R& r, const string& sep) { auto it = ranges::begin(r); auto last = ranges::end(r); ostringstream oss; if (it != last) oss << *it++; for (; it != last; ++it) { oss << sep << *it; } cout << oss.str() << endl; } vector minfact; void pfactinit(int n) { minfact.assign(n+1,0); rep2(2,n+1,i) { if (minfact[i] != 0) continue; minfact[i] = i; rep3(i,n+1,i,j) if (minfact[j] == 0) minfact[j] = i; } } vector> pfact(int n) { vector> factors; while (minfact[n] != 0) { int fact = minfact[n]; int cnt{0}; while (minfact[n] == fact) { n /= fact; ++cnt; } factors.push_back({fact,cnt}); } return factors; } int main() { string s; int m; cin >> s >> m; Aho<'A', 'Z'> aho; rep(m, i) { string c; cin >> c; aho.add(c); } aho.init(); aho.search(s); int ans = 0; rep(m, i) { ans += aho.count(i); } cout << ans << endl; // int n, k; // cin >> n >> k; // Aho aho; // rep(k, i) { // string s; // cin >> s; // aho.add(s); // } // aho.init(); // Mat mat(aho.nodes.size(), aho.nodes.size()); // rep(aho.nodes.size(), i) { // if (aho.nodes[i].term) continue; // rep(26, j) { // mat.data[aho.nodes[i].move[j]][i]++; // } // } // Mat first(aho.nodes.size(), 1); // first.data[0][0] = 1; // Mat res = mat.pow(n) * first; // mint ans; // rep(aho.nodes.size(), i) { // if (!aho.nodes[i].term) { // ans += res.data[i][0]; // } // } // cout << ans << endl; }