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 Ruby (judge verdict: Accepted)

a = gets.chomp
b = gets.chomp
M = gets.to_i

# k: 桁（n桁の数字について調べているときは n-1 は1の位を表す）
# f: 上限と等しい場合 0 そうでない場合 1
# u: 1（より大きい数字を探す）or 0（より小さい数字を探す）
# pre: 一桁左の数字
# mod: m での mod
# zero: 調べている位より上が全部0の場合 true そうでない場合 false
def get(k, f, u, pre, mod, zero)
    if k == @n
        return zero ? 0
         : mod==0 ? 1
         : 0
    end
    res = 0
    if zero
        res += get(k+1,1,0,0,0,true);
        (1..9).each do |i|
            res += get(k+1,1,0,i, i % M,false);
            if k+1 != @n
                res += get(k+1,1,1,i,i % M,false);
            end
        end
        return res % 10000
    end
    if @dp[k][f][u][pre][mod] != nil
        return @dp[k][f][u][pre][mod]
    end
    if f == 1
        if u == 1
            ((pre+1)..9).each do |i|
                res += get(k+1,1,0,i,(mod*10+i) % M,false)
            end
        else
            (0..(pre-1)).each do |i|
                # puts "#{k+1},#{1},#{1},#{p},(mod*10+i) % M"
                res += get(k+1,1,1,i,(mod*10+i) % M,false)
            end
        end
    else
        if u == 1
            ((pre+1)..@s[k]).each do |i|
                if i == @s[k]
                    res += get(k+1,0,0,i,(mod*10+i) % M,false)
                else
                    res += get(k+1,1,0,i,(mod*10+i) % M,false)
                end
            end
        else
            (0..[pre-1, @s[k]].min).each do |i|
                if i == @s[k]
                    res += get(k+1,0,1,i,(mod*10+i) % M,false)
                else
                    res += get(k+1,1,1,i,(mod*10+i) % M,false)
                end
            end
        end
    end
    res = res % 10000
    @dp[k][f][u][pre][mod] = res
    return res
end

def calc(r)
    @n = r.length
    @s = r.split("").map(&:to_i)
    @dp = Array.new(@n+1)
    (0..@n).each do |i|
        @dp[i] = Array.new(2)
        (0..1).each do |j|
            @dp[i][j] = Array.new(2)
            (0..1).each do |k|
                @dp[i][j][k] = Array.new(10)
                (0..9).each do |l|
                    @dp[i][j][k][l] = Array.new(M)
                end
            end
        end
    end
    res = 0
    res += get(1, 1, 0, 0, 0, true)
    (1..@s[0]).each do |i|
        if i == @s[0]
            res += get(1,0,0,i,i % M,false)
            if @n != 1
                res += get(1,0,1,i,i % M,false)
            end
        else
            res += get(1,1,0,i,i % M,false)
            if @n != 1
                res += get(1,1,1,i,i % M,false)
            end
        end
    end
    return res % 10000
end

def judge(r)
    array = r.split("").map(&:to_i)
    pre_diff = nil
    (0..(array.length-2)).each do |i|
        diff = array[i] - array[i+1]
        return false if diff == 0
        if pre_diff == nil
            pre_diff = diff
            next
        end

        if pre_diff * diff < 0
            pre_diff = diff
        else
            return false
        end
    end
end

puts (calc(b) - calc(a) + 10000 + (judge(a) ? 1 : 0)) % 10000