use std::{cmp::Ordering, collections::HashMap, hash::Hash}; use proconio::{input, marker::Bytes}; // 0. 決定性有限オートマトン trait Dfa { type State; type Alphabet; fn init(&self) -> Self::State; fn next(&self, q: &Self::State, c: &Self::Alphabet) -> Self::State; fn accept(&self, q: &Self::State) -> bool; } // 1. Contains(w) は w がつく数を認識するオートマトン struct Contains { next: Vec<[usize; 10]>, accept: Vec, } impl Contains { fn new(w: &[u8]) -> Self { // 1-1. w を一列に並べる let n = w.len(); let mut next = vec![[0; 10]; n + 1]; let mut accept = vec![false; n + 1]; for q in 0..n { next[q][(w[q] - b'0') as usize] = q + 1; } accept[n] = true; // 1-2. failure 辺を張る let mut fail = vec![0; n + 1]; for q in 1..=n { for c in 0..10 { if next[q][c] != 0 { fail[next[q][c]] = next[fail[q]][c]; } else { next[q][c] = next[fail[q]][c]; } } } // 1-3. 受理状態に留まるようにする next[n] = [n; 10]; Contains { next, accept } } } impl Dfa for Contains { type State = usize; type Alphabet = u8; fn init(&self) -> Self::State { 0 } fn next(&self, q: &Self::State, c: &Self::Alphabet) -> Self::State { self.next[*q][(c - b'0') as usize] } fn accept(&self, q: &Self::State) -> bool { self.accept[*q] } } // 2. Not(a) は a が認識しない数を認識するオートマトン struct Not(A); impl Dfa for Not { type State = A::State; type Alphabet = A::Alphabet; fn init(&self) -> Self::State { self.0.init() } fn next(&self, q: &Self::State, c: &Self::Alphabet) -> Self::State { self.0.next(q, c) } fn accept(&self, q: &Self::State) -> bool { !self.0.accept(q) } } // 3. And(a, b) は a と b がともに認識する数を認識するオートマトン struct And(A, B); impl> Dfa for And { type State = (A::State, B::State); type Alphabet = A::Alphabet; fn init(&self) -> Self::State { (self.0.init(), self.1.init()) } fn next(&self, q: &Self::State, c: &Self::Alphabet) -> Self::State { (self.0.next(&q.0, c), self.1.next(&q.1, c)) } fn accept(&self, q: &Self::State) -> bool { self.0.accept(&q.0) && self.1.accept(&q.1) } } // 4. Le(n) は n 以下の数を認識するオートマトン struct Le<'a>(&'a [u8]); impl Dfa for Le<'_> { type State = (Ordering, usize); type Alphabet = u8; fn init(&self) -> Self::State { (Ordering::Equal, 0) } fn next(&self, q: &Self::State, c: &Self::Alphabet) -> Self::State { (q.0.then(c.cmp(&self.0[q.1])), q.1 + 1) } fn accept(&self, q: &Self::State) -> bool { q.0.is_le() } } const MOD: u64 = 998_244_353; // 5. count(a, Σ, n) は a が認識する言語と Σ^n の共通部分を 998244353 で割った余りで数える fn count(dfa: A, sigma: S, len: usize) -> u64 where A: Dfa, A::State: Eq + Hash, S: Iterator + Clone, { let mut dp = HashMap::new(); dp.insert(dfa.init(), 1); for _ in 0..len { let mut ndp = HashMap::new(); for (q, v) in dp { for c in sigma.clone() { let e = ndp.entry(dfa.next(&q, &c)).or_insert(0); *e = (*e + v) % MOD; } } dp = ndp; } dp.iter() .filter_map(|(q, v)| dfa.accept(q).then_some(v)) .fold(0, |sum, v| (sum + v) % MOD) } // 6. Just Do It !!!! fn main() { input!(n: Bytes); let dfa = And(Not(Contains::new(b"404")), Le(&n)); println!("{}", (count(dfa, b'0'..=b'9', n.len()) + MOD - 1) % MOD); }