結果
| 問題 |
No.430 文字列検索
|
| コンテスト | |
| ユーザー |
IKyopro
|
| 提出日時 | 2020-10-29 16:02:53 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 12 ms / 2,000 ms |
| コード長 | 4,719 bytes |
| コンパイル時間 | 2,299 ms |
| コンパイル使用メモリ | 214,376 KB |
| 最終ジャッジ日時 | 2025-01-15 16:21:49 |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 14 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T> using vec = vector<T>;
template<class T> using vvec = vector<vec<T>>;
template<class T> bool chmin(T& a,T b){if(a>b) {a = b; return true;} return false;}
template<class T> bool chmax(T& a,T b){if(a<b) {a = b; return true;} return false;}
#define all(x) (x).begin(),(x).end()
#define debug(x) cerr << #x << " = " << (x) << endl;
template<int char_size,int margin>
class Trie{
private:
struct Node{
int ne[char_size];
int num;
int subtree_num;
vec<int> accept;
Node():num(0){
memset(ne,-1,sizeof(ne));
}
};
int root;
public:
vec<Node> nodes;
Trie():root(0){
nodes.push_back(Node());
}
void update_direct(int node,int id){
nodes[node].accept.push_back(id);
nodes[node].num++;
}
void update_child(int node,int child){
nodes[node].subtree_num++;
}
void add(const string& S,int s_id,int node_id,int id){
if(s_id==S.size()) update_direct(node_id,id);
else{
int c = S[s_id]-margin;
if(nodes[node_id].ne[c]==-1){
nodes[node_id].ne[c] = (int) nodes.size();
nodes.push_back(Node());
}
add(S,s_id+1,nodes[node_id].ne[c],id);
update_child(node_id,nodes[node_id].ne[c]);
}
}
void add(const string& S,int id){
add(S,0,0,id);
}
void add(const string &S){
add(S,nodes[0].num);
}
template<class F>
void query(const string& S,F& f,int s_id,int node_id){
for(auto& id:nodes[node_id].accept) f(id);
if(s_id==S.size()) return ;
else{
int c = S[s_id]-margin;
if(nodes[node_id].ne[c]==-1) return ;
query(S,f,s_id+1,nodes[node_id].ne[c]);
}
}
template<class F>
void query(const string& S,F& f){
query(S,f,0,0);
}
int count()const{
return nodes[0].num;
}
int size()const{
return (int) nodes.size();
}
};
template<int char_size,int margin>
struct AhoCorasick:Trie<char_size+1,margin>{
using Trie<char_size+1,margin>::Trie;
const int FAIL = char_size;
vec<int> cnt;
void build(bool heavy=true){
int n = this->size();
cnt.resize(n);
for(int i=0;i<n;i++){
cnt[i] = (int) this->nodes[i].accept.size();
}
queue<int> Q;
for(int i=0;i<=char_size;i++){
if(~this->nodes[0].ne[i]){
this->nodes[this->nodes[0].ne[i]].ne[FAIL] = 0;
Q.push(this->nodes[0].ne[i]);
}else{
this->nodes[0].ne[i] = 0;
}
}
while(!Q.empty()){
auto &now = this->nodes[Q.front()];
cnt[Q.front()] += cnt[now.ne[FAIL]];
Q.pop();
int f = now.ne[FAIL];
for(int i=0;i<char_size;i++){
if(~now.ne[i]){
this->nodes[now.ne[i]].ne[FAIL] = this->nodes[f].ne[i];
if(heavy){
auto &u = this->nodes[now.ne[i]].accept;
auto &v = this->nodes[this->nodes[f].ne[i]].accept;
vec<int> acc;
set_union(all(u),all(v),back_insert_iterator(acc));
u = acc;
}
Q.push(now.ne[i]);
}else{
now.ne[i] = this->nodes[f].ne[i];
}
}
}
}
map<int,int> match(string &S,int now=0){
map<int,int> res;
for(auto& c:S){
while(this->nodes[now].ne[c-margin]==-1){
now = this->nodes[now].ne[FAIL];
}
now = this->nodes[now].ne[c-margin];
for(auto& v:this->nodes[now].accept) res[v]++;
}
return res;
}
pair<ll, int > move(const char &c, int now = 0) {
now = this->nodes[now].ne[c - margin];
return {cnt[now], now};
}
pair<ll, int > move(const string &str, int now = 0) {
ll sum = 0;
for(auto &c : str) {
auto ne = move(c, now);
sum += ne.first;
now = ne.second;
}
return {sum, now};
}
};
int main(){
cin.tie(0);
ios::sync_with_stdio(false);
string S;
cin >> S;
int M;
cin >> M;
AhoCorasick<26,'A'> ushi;
for(int i=0;i<M;i++){
string s;
cin >> s;
ushi.add(s);
}
ushi.build();
auto res = ushi.match(S);
ll ans = 0;
for(auto& x:res){
ans += x.second;
}
cout << ushi.move(S).first << "\n";
}
IKyopro