結果

問題 No.430 文字列検索
ユーザー srtry
提出日時 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

ソースコード

diff #

/* 
 *     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(&current_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[&current_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[&current_node.failure].length;
            },

            (false,true) => {
                was_failure = true;
                r+=1;
                l+=1;
            },
        }
    }
    write!(out, "{}", ans).unwrap();
}
0