Problem:
ジグザグ数 (Zig-Zag Numbers)

問題

正の整数を (先頭に 0 をつけずに) 10 進法で書いて桁の数字を順番に見ていくと増加と減少を交互に繰り返しているとき，その数は「ジグザグ数」であると呼ぶことにしよう．たとえば，2947 は桁の数字が 2 → 9 → 4 → 7 と，増加 → 減少 → 増加 の順になっているのでジグザグ数である．また，71946 は 減少 → 増加 → 減少 → 増加 の順なのでジグザグ数である．一方，123 や 71446 や 71442 や 88 はジグザグ数ではない．なお，1 桁の正の整数はジグザグ数であると考えることとする．

A 以上 B 以下の M の倍数のうち，ジグザグ数の個数を 10000 で割った余りを求めるプログラムを作成せよ．

入力

入力は 3 行からなり，1 行に 1 つずつ正の整数が書かれている．

1 行目の整数は A を，2 行目の整数は B を，3 行目の整数は M を表す．これらは 1 ≦ A ≦ B ≦ 10500，1 ≦ M ≦ 500 を満たす．

※ A や B の値は，通常の整数を表すデータ型には収まらない可能性があることに注意せよ．

出力

A 以上 B 以下の M の倍数のうち，ジグザグ数の個数を 10000 で割った余りを 1 行で出力せよ．

入出力例

入力例 1

100
200
5

出力例 1

13

入出力例 1 において，100 以上 200 以下の 5 の倍数であるジグザグ数は，105, 120, 130, 140, 150, 160, 165, 170, 175, 180, 185, 190, 195 の 13 個である．

入力例 2

6
1234567
3

出力例 2

246

入出力例 2 において，6 以上 1234567 以下の 3 の倍数であるジグザグ数は 50246 個あるので，それを 10000 で割った余りである 246 を出力する．

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in Rust (judge verdict: Accepted)

#[allow(unused_imports)]
use std::io::{stdin, Read, StdinLock};
#[allow(unused_imports)]
use std::cmp::{max, min, Ordering};
#[allow(unused_imports)]
use std::str::FromStr;
#[allow(unused_imports)]
use std::collections::{HashSet, HashMap, BinaryHeap, VecDeque};
#[allow(unused_imports)]
use std::vec::Vec;

#[allow(dead_code)]
const INF: i32 = 1000_000_000;
#[allow(dead_code)]
const INFLL: i64 = 1000_000_000_000_000_000;
#[allow(dead_code)]
const EPS: f64 = 1.0e-10;
#[allow(dead_code)]
const MOD: i32 = 1000_000_007;
#[allow(dead_code)]
const MODLL: i64 = 1000_000_007;

struct Scanner<'a> {
    cin: StdinLock<'a>,
}

#[allow(dead_code)]
impl<'a> Scanner<'a> {
    fn new(cin: StdinLock<'a>) -> Scanner<'a> {
        Scanner {cin: cin}
    }
    fn read1<T: FromStr>(&mut self) -> Option<T> {
        let token = self.cin.by_ref().bytes().map(|c| c.unwrap() as char)
                    .skip_while(|c| c.is_whitespace())
                    .take_while(|c| !c.is_whitespace())
                    .collect::<String>();
        token.parse::<T>().ok()
    }
    fn read<T: FromStr>(&mut self) -> T {
        self.read1().unwrap()
    }
}

fn solve(a: String, m: usize, f: usize) -> i32 {
    // dp[i][less][mod m][pre][up]
    let a: Vec<char> = a.chars().collect();
    let mut dp: Vec<Vec<Vec<Vec<Vec<i32>>>>> = vec![vec![vec![vec![vec![0; 2]; 10]; m]; 2]; a.len() + 1];
    for i in 0..a.len() {
        let cur = a[i].to_digit(10).unwrap();
        for le in 0..2 {
            for j in 0..m {
                for pre in 0..10 {
                    for k in 0..2 {
                        let lb = if k == 1 { pre + 1 } else { 0 };
                        let ub = if le == 1 { 10 } else { cur + 1 };
                        let ub = if k == 0 { min(ub, pre) } else { ub };
                        if lb >= ub {
                            continue;
                        }
                        for d in lb..ub {
                            let nle: usize = if le == 1 || d < cur { 1 } else { 0 };
                            let nk: usize = if k == 0 { 1 } else { 0 };
                            let nj: usize = (j * 10 + d as usize) % m;
                            let d = d as usize;
                            let pre = pre as usize;
                            dp[i + 1][nle][nj][d][nk] += dp[i][le][j][pre][k];
                            dp[i + 1][nle][nj][d][nk] %= 10000;
                        }
                    }
                }
            }
        }
        let ub = if i == 0 { cur + 1 } else { 10 };
        for j in 1..ub {
            let le = if i != 0 || j != cur { 1 } else { 0 };
            let le = le as usize;
            let j = j as usize;
            dp[i + 1][le][j % m][j][0] += 1;
            if i + 1 != a.len() {
                dp[i + 1][le][j % m][j][1] += 1;
            }
        }
    }

    let mut ans = 0;
    for i in 0..10 {
        for j in 0..2 {
            ans = (ans + dp[a.len()][1][0][i][j]) % 10000;
            if f == 1 {
                ans = (ans + dp[a.len()][0][0][i][j]) % 10000;
            }
        }
    }
    ans
}

fn main() {
    let cin = stdin();
    let cin = cin.lock();
    let mut sc = Scanner::new(cin);

    let (a, b, m): (String, String, usize) = (sc.read(), sc.read(), sc.read());
    let x = solve(a, m, 0);
    let y = solve(b, m, 1);
    let ans = (y - x + 10000) % 10000;
    println!("{}", ans);
}