/* * Author: srtry * Created: 2025-10-11T04:41:48+09:00 * Coding: utf-8-unix */ use proconio::input; use proconio::marker::{Chars}; use std::collections::{HashSet,HashMap,BTreeSet}; use std::io::{stdout,Write,BufWriter}; use std::u8; #[derive(PartialEq,Eq,Hash,Debug,Clone)] struct node { length:usize, children:[bool;26], direct_cnt:usize, failure:usize, } impl node { fn new() -> Self { node {length: 0, children: [false;26], direct_cnt: 0, failure:0} } } fn hash(x:&[char]) -> usize { let mut tmp: usize = 0; for ch in x.iter().rev() { tmp = tmp*27 + 1 + (*ch as u8 - b'A') as usize } return tmp } fn main() { input!{ s:Chars, m:usize, c:[Chars;m] } let out = stdout(); let mut out = BufWriter::new(out.lock()); // trieの構築 let mut trie:HashMap = HashMap::new(); trie.insert(0,node::new()); let mut parent_hash:usize = 0; for c_elem in c.iter() { parent_hash = 0; for i in 1..=c_elem.len() { let hash = hash(&c_elem[0..i]); let idx: usize = c_elem[i-1] as usize - b'A' as usize; let mut node = node{ length:i, children:[false;26], direct_cnt:0, failure:0 }; if i==c_elem.len() { node.direct_cnt = 1; } // 現在ノードのハッシュが存在するか // 存在  => direct_cntの更新、parent_hashを今のハッシュに // 非存在 => trieに追加、parent_hashを今のハッシュに if let Some(x) = trie.get_mut(&hash) { x.direct_cnt = node.direct_cnt.max(x.direct_cnt); } else { trie.insert(hash, node); } // 親ノードのchildrenを更新 trie.get_mut(&parent_hash).unwrap().children[idx] = true; // 今回のノードを親ノードへ parent_hash = hash; } } // failureの構築 let hashes:HashSet = trie.keys().cloned().collect(); for (hash,node) in trie.iter_mut() { let mut failure_hash = hash.clone(); for i in (0..node.length).rev() { failure_hash /= 27; if hashes.contains(&failure_hash) { node.failure = failure_hash; break; } } } // direct_cntの更新 let trie_ = trie.clone(); for node in trie.values_mut() { let mut failure_node = trie_.get(&node.failure).unwrap(); loop { if failure_node.length==0 { break; } if failure_node.direct_cnt == 1 { node.direct_cnt += 1; } failure_node = trie_.get(&failure_node.failure).unwrap(); } } // 検索 let mut l = 0; let mut r = 0; let mut was_failure:bool = true; let mut current_node:&node; let mut ans = 0; loop { let current_hash = hash(&s[l..r]); current_node = if let Some(x) = trie.get(¤t_hash) { x } else { &trie[&0] }; if !was_failure { ans += current_node.direct_cnt; } if l>=s.len() { break; } // 遷移判定 if r==s.len() { was_failure = true; l += current_node.length - trie[¤t_node.failure].length; continue; } match (current_node.children[s[r] as usize - b'A' as usize], l==r) { (true,_) => { was_failure = false; r = (r+1).min(s.len()); } (false,false) => { was_failure = true; l += current_node.length - trie[¤t_node.failure].length; }, (false,true) => { was_failure = true; r+=1; l+=1; }, } } write!(out, "{}", ans).unwrap(); }