結果
問題 |
No.430 文字列検索
|
ユーザー |
|
提出日時 | 2025-10-11 22:10:32 |
言語 | Rust (1.83.0 + proconio) |
結果 |
AC
|
実行時間 | 19 ms / 2,000 ms |
コード長 | 4,101 bytes |
コンパイル時間 | 12,100 ms |
コンパイル使用メモリ | 398,232 KB |
実行使用メモリ | 7,716 KB |
最終ジャッジ日時 | 2025-10-11 22:10:47 |
合計ジャッジ時間 | 13,609 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 14 |
コンパイルメッセージ
warning: unused import: `BTreeSet` --> src/main.rs:9:40 | 9 | use std::collections::{HashSet,HashMap,BTreeSet}; | ^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: type `node` should have an upper camel case name --> src/main.rs:14:8 | 14 | struct node { | ^^^^ help: convert the identifier to upper camel case: `Node` | = note: `#[warn(non_camel_case_types)]` on by default warning: value assigned to `parent_hash` is never read --> src/main.rs:45:13 | 45 | let mut parent_hash:usize = 0; | ^^^^^^^^^^^ | = help: maybe it is overwritten before being read? = note: `#[warn(unused_assignments)]` on by default warning: unused variable: `i` --> src/main.rs:79:13 | 79 | for i in (0..node.length).rev() { | ^ help: if this is intentional, prefix it with an underscore: `_i` | = note: `#[warn(unused_variables)]` on by default
ソースコード
/* * 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<usize,node> = 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<usize> = 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(); }