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 JAVA (judge verdict: Wrong Answer)

import java.math.BigInteger;
import java.util.Scanner;

//Zig-Zag Numbers
public class Main{

	int MOD, M = 10000;
	
	int[] s;
	int n;
	//idx, free, isUp, pre, M
	int[][][][][] dp;
	
	int get(int k, int f, int u, int pre, int m, boolean zero){
		if(k==n)return zero?0:m==0?1:0;
		int res = 0;
		if(zero){
			res+=get(k+1,f,u,0,0,true);
			for(int p=1;p<10;p++){
				res+=get(k+1,f,0,p,p%MOD,false);
				if(k+1!=n)res+=get(k+1,f,1,p,p%MOD,false);
			}
			return res%M;
		}
		if(dp[k][f][u][pre][m]!=-1)return dp[k][f][u][pre][m];
		if(f==1){
			if(u==1){
				for(int p=pre+1;p<10;p++){
					res+=get(k+1,f,1-u,p,(m*10+p)%MOD,false);
				}
			}
			else{
				for(int p=0;p<pre;p++){
					res+=get(k+1,f,1-u,p,(m*10+p)%MOD,false);
				}
			}
		}
		else{
			if(u==1){
				for(int p=pre+1;p<=s[k];p++){
					if(p==s[k])res+=get(k+1,0,1-u,p,(m*10+p)%MOD,false);
					else res+=get(k+1,1,1-u,p,(m*10+p)%MOD,false);
				}
			}
			else{
				int t = Math.min(pre-1, s[k]);
				for(int p=0;p<=t;p++){
					if(p==s[k])res+=get(k+1,0,1-u,p,(m*10+p)%MOD,false);
					else res+=get(k+1,1,1-u,p,(m*10+p)%MOD,false);
				}
			}
		}
		return dp[k][f][u][pre][m] = res%M;
	}
	
	int f(String r){
		n = r.length();
		s = new int[n];
		for(int i=0;i<n;i++)s[i]=r.charAt(i)-'0';
		dp = new int[n+1][2][2][10][MOD];
		for(int i=0;i<=n;i++)for(int j=0;j<2;j++)for(int k=0;k<2;k++)for(int p=0;p<10;p++)for(int m=0;m<MOD;m++)dp[i][j][k][p][m]=-1;
		int res = 0;
		res += get(1, 1, 0, 0, 0, true);
		for(int p=1;p<=s[0];p++){
			if(p==s[0]){
				res+=get(1,0,0,p,p%MOD,false);
				if(n!=1)res+=get(1,0,1,p,p%MOD,false);
			}
			else{
				res+=get(1,1,0,p,p%MOD,false);
				if(n!=1)res+=get(1,1,1,p,p%MOD,false);
			}
		}
		return res%M;
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		String A = sc.nextBigInteger().subtract(BigInteger.ONE).toString(), B = sc.next();
		MOD = sc.nextInt();
		System.out.println(f(B)-f(A));
	}
	
	public static void main(String[] args) {
		new Main().run();
	}
}