結果
| 問題 |
No.430 文字列検索
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2021-09-08 17:00:24 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 68 ms / 2,000 ms |
| コード長 | 5,406 bytes |
| コンパイル時間 | 1,345 ms |
| コンパイル使用メモリ | 95,888 KB |
| 最終ジャッジ日時 | 2025-01-24 08:52:40 |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 14 |
ソースコード
#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;
}