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 ≦ 10
500
，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 を出力する．
問題文と自動審判に使われるデータは、
情報オリンピック日本委員会
が作成し公開している問題文と採点用テストデータです。

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

#define REP(i,n) for(int i=0;i<(int)(n);i++)
#define ALL(x) (x).begin(),(x).end()

using namespace std;

using ll = long long;
using ld = long double;

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }

struct yes_no : numpunct<char> {
  string_type do_truename()  const { return "Yes"; }
  string_type do_falsename() const { return "No"; }
};

template<int M>
class Modulo {
  using ll = long long;
  int n;
public:
  Modulo () : n(0) {;}
  Modulo (int m) : n(m) {
    if (n >= M) n %= M;
    else if (n < 0) n = (n % M + M) % M;
  }
  Modulo (ll m) {
    if (m >= M) m %= M;
    else if (m < 0) m = (m % M + M) % M;
    n = m;
  }
  explicit operator int() const { return n; }
  explicit operator ll() const { return n; }
  bool operator==(const Modulo &a) const { return n == a.n; }
  Modulo operator+=(const Modulo &a) { n += a.n; if (n >= M) n -= M; return *this; }
  Modulo operator-=(const Modulo &a) { n -= a.n; if (n < 0) n += M; return *this; }
  Modulo operator*=(const Modulo &a) { n = (ll(n) * a.n) % M; return *this; }
  Modulo operator+(const Modulo &a) const { Modulo res = *this; return res += a; }
  Modulo operator-(const Modulo &a) const { Modulo res = *this; return res -= a; }
  Modulo operator*(const Modulo &a) const { Modulo res = *this; return res *= a; }
};

const int mod = 10000;

using Mod = Modulo<mod>;

int M;
Mod zig_le[512][512][10], zig_gt[512][512][10];
Mod zag_le[512][512][10], zag_gt[512][512][10];

Mod dp(string s) {
  if (s.size() <= 1) return stoi(s) / M;
  REP(i,512) REP(j,512) REP(k,10) {
    zig_le[i][j][k] = 0;
    zig_gt[i][j][k] = 0;
    zag_le[i][j][k] = 0;
    zag_gt[i][j][k] = 0;
  }
  reverse(ALL(s));
  const int n = s.size();
  REP(k,10) {
    const int d = s[0] - '0';
    if (k <= d) zig_le[0][k % M][k] = zag_le[0][k % M][k] = 1;
    else zig_gt[0][k % M][k] = zag_gt[0][k % M][k] = 1;
  }
  int base = 1;
  Mod res = 9 / M;
  REP(i,n-1) {
    base = (base * 10) % M;
    const int d = s[i+1] - '0';
    REP(j,512) REP(k,10) REP(l,10) {
      if (k < l) {
        if (l < d) zig_le[i+1][(base * l + j) % M][l] += zag_le[i][j][k] + zag_gt[i][j][k];
        else if (l > d) zig_gt[i+1][(base * l + j) % M][l] += zag_le[i][j][k] + zag_gt[i][j][k];
        else {
          zig_le[i+1][(base * l + j) % M][l] += zag_le[i][j][k];
          zig_gt[i+1][(base * l + j) % M][l] += zag_gt[i][j][k];
        }
      }
      else if (k > l) {
        if (l < d) zag_le[i+1][(base * l + j) % M][l] += zig_le[i][j][k] + zig_gt[i][j][k];
        else if (l > d) zag_gt[i+1][(base * l + j) % M][l] += zig_le[i][j][k] + zig_gt[i][j][k];
        else {
          zag_le[i+1][(base * l + j) % M][l] += zig_le[i][j][k];
          zag_gt[i+1][(base * l + j) % M][l] += zig_gt[i][j][k];
        }
      }
    }
    if (i < n - 2) {
      for (int l = 1; l < 10; ++l) {
        res += zig_le[i+1][0][l];
        res += zig_gt[i+1][0][l];
        res += zag_le[i+1][0][l];
        res += zag_gt[i+1][0][l];
      }
    }
    else {
      for (int l = 1; l < 10; ++l) {
        res += zig_le[i+1][0][l];
        res += zag_le[i+1][0][l];
      }
    }
  }
  return res;
}

int main() {
  locale loc(locale(), new yes_no);
  cout << boolalpha;
  cout.imbue(loc);
  string A, B;
  cin >> A >> B >> M;
  A.back()--;
  for (int i = int(A.size()) - 1; i >= 1; --i) {
    if (A[i] < '0') {
      A[i] += 10;
      A[i-1] -= 1;
    }
  }
  cout << int(dp(B) - dp(A)) << endl;
  return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 44408
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
const int P=10000;
int m,f[510][10][510][3][2];
string s;
int solve(int k,int last,int r,int x,int g){
	if(k>=(int)s.size()) return!r;
	int &res=f[k][last][r][x][g];
	if(res!=-1) return res;
	res=0;
	int mx=g?9:s[k]-'0';
	if(x==1){
		for(int i=0;i<=min(last-1,mx);i++)
			res+=solve(k+1,i,(r*10+i)%m,!x,g||i<mx);
	}else if(x==0){
		for(int i=last+1;i<=mx;i++)
		res+=solve(k+1,i,(r*10+i)%m,!x,g||i<mx);
	}else{
		for(int i=0;i<=mx;i++){
		if(last==0) res+=solve(k+1,i,(r*10+i)%m,2,g||i<mx);
		else if(i!=last)
			res+=solve(k+1,i,(r*10+i)%m,last<i,g||i<mx);
		}
	}
	return res%=P;
}
int main(){
	string a,b;
	cin>>a>>b>>m;
	a.back()--;
	for(int i=(int)a.size()-1;i>0;i--)
		if(a[i]<'0'){
			a[i]+=10;
			a[i-1]--;
		}
	s=b;
	memset(f,-1,sizeof(f));
	int ans=solve(0,0,0,2,0);
	s=a;
	memset(f,-1,sizeof(f));
	ans-=solve(0,0,0,2,0);
	while(ans<0) ans+=P;
	cout<<ans<<"\n";
 return 0;
}
accuracy: 1
time_ms: 260
memory_kb: 64272
final_rank: 8

code_snippet: #include <bits/stdc++.h>
#define int long long
using namespace std;
int M,dp[501][501][10][3][2][2];
string A,B;
int dfs(string s,int x,int mod,int b,int flag1,bool f,bool zero){
	if (x == s.size()){
		return (!zero && mod == 0);
	}if (dp[x][mod][b][flag1][f][zero] >= 0){
		return dp[x][mod][b][flag1][f][zero];
	}
	int limit = f?(s[x] - '0'):9;
	int cnt = 0;
	for (int d = 0;d <= limit;d++){
		bool new_tight = f && (d == limit);
		bool new_zero = zero && (d == 0);
		int new_mod = (mod * 10 + d) % M;
		if (new_zero){
			cnt += dfs(s,x + 1,new_mod,b,flag1,new_tight,new_zero);
			cnt %= 10000;
			continue;
		}
		int new_d = flag1;
		if (zero){
			new_d = 0;
		}else{
			if (flag1 == 0){
				if (d > b){
					new_d = 1;
				}else if (d < b){
					new_d = 2;
				}else{
					continue;
				}
			}else if (flag1 == 1){
				if (d >= b){
					continue;
				}
				new_d = 2;
			}else if (flag1 == 2){
				if (d <= b){
					continue;
				}
				new_d = 1;
			}
		}
		cnt += dfs(s,x + 1,new_mod,d,new_d,new_tight,0);
		cnt %= 10000;
	}
	return dp[x][mod][b][flag1][f][zero] = cnt;
}
int solve(string s){
	memset(dp,-0x3f,sizeof(dp));
	return dfs(s,0,0,0,0,1,1);
}
bool check(string s){
	if (s.size() == 1){
		return true;
	}
	int flag1 = 0;
	for (int i = 1;i < s.size();i++){
		if (s[i] > s[i - 1]){
			if (flag1 == 1){
				return false;
			}
			flag1 = 2;
		}else if (s[i] < s[i - 1]){
			if (flag1 == 2){
				return false;
			}
			flag1 = 1;
		}else{
			return false;
		}
	}
	return true;
}
int mod(string s,int m){
	int cnt = 0;
	for (char c:s){
		cnt = (cnt * 10 + (c - '0')) % m;
	}
	return cnt;
}
signed main(){
	cin >> A >> B >> M;
	int ans = 0;
	ans = solve(B) - solve(A);
	if (mod(A,M) == 0 && check(A)){
		ans++;
	}
	ans = (ans % 10000 + 10000) % 10000;
	cout << ans << "\n";
	return 0;
}
accuracy: 1
time_ms: 1860
memory_kb: 239020
final_rank: 20

code_snippet: #pragma region Macros
#include <bits/stdc++.h>

using namespace std;
using lint = long long;
using ull = unsigned long long;
using ld = long double;
using int128 = __int128_t;
#define all(x) (x).begin(), (x).end()
#define EPS 1e-8
#define uniqv(v) v.erase(unique(all(v)), v.end())
#define OVERLOAD_REP(_1, _2, _3, name, ...) name
#define REP1(i, n) for (auto i = std::decay_t<decltype(n)>{}; (i) != (n); ++(i))
#define REP2(i, l, r) for (auto i = (l); (i) != (r); ++(i))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP2, REP1)(__VA_ARGS__)
#define log(x) cout << x << endl
#define logfixed(x) cout << fixed << setprecision(10) << x << endl;
#define logy(bool)             \
    if (bool) {                \
        cout << "Yes" << endl; \
    } else {                   \
        cout << "No" << endl;  \
    }

ostream& operator<<(ostream& dest, __int128_t value) {
    ostream::sentry s(dest);
    if (s) {
        __uint128_t tmp = value < 0 ? -value : value;
        char buffer[128];
        char* d = end(buffer);
        do {
            --d;
            *d = "0123456789"[tmp % 10];
            tmp /= 10;
        } while (tmp != 0);
        if (value < 0) {
            --d;
            *d = '-';
        }
        int len = end(buffer) - d;
        if (dest.rdbuf()->sputn(d, len) != len) {
            dest.setstate(ios_base::badbit);
        }
    }
    return dest;
}

template <typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    for (int i = 0; i < (int)v.size(); i++) {
        os << v[i] << (i + 1 != (int)v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream& operator<<(ostream& os, const set<T>& set_var) {
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end()) os << " ";
        itr--;
    }
    return os;
}

template <typename T, typename U>
ostream& operator<<(ostream& os, const map<T, U>& map_var) {
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << itr->first << " -> " << itr->second << "\n";
    }
    return os;
}

template <typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& pair_var) {
    os << "(" << pair_var.first << ", " << pair_var.second << ")";
    return os;
}

void out() { cout << '\n'; }
template <class T, class... Ts>
void out(const T& a, const Ts&... b) {
    cout << a;
    (cout << ... << (cout << ' ', b));
    cout << '\n';
}

template <typename T>
istream& operator>>(istream& is, vector<T>& v) {
    for (T& in : v) is >> in;
    return is;
}

inline void in(void) { return; }
template <typename First, typename... Rest>
void in(First& first, Rest&... rest) {
    cin >> first;
    in(rest...);
    return;
}

template <typename T>
bool chmax(T& a, const T& b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
template <typename T>
bool chmin(T& a, const T& b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

vector<lint> dx8 = {1, 1, 0, -1, -1, -1, 0, 1};
vector<lint> dy8 = {0, 1, 1, 1, 0, -1, -1, -1};
vector<lint> dx4 = {1, 0, -1, 0};
vector<lint> dy4 = {0, 1, 0, -1};

#pragma endregion

// ジグザグ数を受理するDFA
class Zig {
   public:
    using Alphabet = char;
    struct State {
        int last;
        bool increasing;
        bool decreasing;

        bool operator==(const State& other) const = default;
    };

    State init() const {
        return {0, false, false};
    }

    State next(State s, const Alphabet& a, size_t i) const {
        if (s.last == -1) {
            return {-1, false, false};
        }
        if (!s.increasing and !s.decreasing and s.last == 0) {
            if (a == '0') {
                return {0, false, false};
            } else {
                return {a - '0', false, false};
            }
        }

        if (!s.increasing and !s.decreasing) {
            if (s.last < a - '0') {
                return {a - '0', true, false};
            } else if (s.last > a - '0') {
                return {a - '0', false, true};
            } else {
                return {-1, false, false};
            }
        }

        if (s.increasing) {
            if (s.last > a - '0') {
                return {a - '0', false, true};
            } else {
                return {-1, false, false};
            }
        }

        if (s.decreasing) {
            if (s.last < a - '0') {
                return {a - '0', true, false};
            } else {
                return {-1, false, false};
            }
        }
        return {-1, false, false};
    }

    bool accept(State s) const {
        return s.last != -1;
    }

    bool successful(State s) const {
        return 0;
    }

    bool unsuccessful(State s) const {
        return s.last == -1;
    }
};

enum class Ordering { Less,
                      Equal,
                      Greater };

namespace std {
template <>
struct hash<Ordering> {
    std::size_t operator()(const Ordering& o) const {
        return std::hash<int>()(static_cast<int>(o));
    }
};
template <typename T1, typename T2>
struct hash<pair<T1, T2>> {
    std::size_t operator()(const pair<T1, T2>& p) const {
        return std::hash<T1>()(p.first) * 31 + std::hash<T2>()(p.second);
    }
};

template <>
struct hash<Zig::State> {
    std::size_t operator()(const Zig::State& s) const {
        return std::hash<int>()(s.last) ^ (std::hash<bool>()(s.increasing) << 1) ^ (std::hash<bool>()(s.decreasing) << 2);
    }
};
}  // namespace std

struct TupleHash {
    size_t operator()(const std::tuple<int, int, int>& t) const {
        auto [x, y, z] = t;
        return std::hash<int>()(x) ^ (std::hash<int>()(y) << 1) ^ (std::hash<int>()(z) << 2);
    }
};
template <typename X>
class Dfa {
   public:
    using Alphabet = typename X::Alphabet;
    using State = typename X::State;

    Dfa(const X& x) : x_(x) {}

    State init() const { return x_.init(); }

    State next(const State& s, const Alphabet& a, size_t i) const {
        return x_.next(s, a, i);
    }

    bool accept(const State& s) const {
        return x_.accept(s);
    }

    bool successful(const State& s) const {
        return x_.successful(s);
    }

    bool unsuccessful(const State& s) const {
        return x_.unsuccessful(s);
    }

   private:
    X x_;
};

template <typename X, typename Y>
class AndDfa {
   public:
    using Alphabet = typename X::Alphabet;
    using State = pair<typename X::State, typename Y::State>;

    AndDfa(const X& x, const Y& y) : x_(x), y_(y) {}

    State init() const { return make_pair(x_.init(), y_.init()); }

    State next(const State& s, const Alphabet& a, size_t i) const {
        return make_pair(x_.next(s.first, a, i), y_.next(s.second, a, i));
    }

    bool accept(const State& s) const {
        return x_.accept(s.first) and y_.accept(s.second);
    }

    bool successful(const State& s) const {
        return x_.successful(s.first) and y_.successful(s.second);
    }

    bool unsuccessful(const State& s) const {
        return x_.unsuccessful(s.first) or y_.unsuccessful(s.second);
    }

   private:
    X x_;
    Y y_;
};

template <typename X, typename Y>
class OrDfa {
   public:
    using Alphabet = typename X::Alphabet;
    using State = pair<typename X::State, typename Y::State>;

    OrDfa(const X& x, const Y& y) : x_(x), y_(y) {}

    State init() const { return make_pair(x_.init(), y_.init()); }

    State next(const State& s, const Alphabet& a, size_t i) const {
        return make_pair(x_.next(s.first, a, i), y_.next(s.second, a, i));
    }

    bool accept(const State& s) const {
        return x_.accept(s.first) or y_.accept(s.second);
    }

    bool successful(const State& s) const {
        return x_.successful(s.first) or y_.successful(s.second);
    }

    bool unsuccessful(const State& s) const {
        return x_.unsuccessful(s.first) and y_.unsuccessful(s.second);
    }

   private:
    X x_;
    Y y_;
};

template <typename X>
class NotDfa {
   public:
    using Alphabet = typename X::Alphabet;
    using State = typename X::State;

    NotDfa(const X& x) : x_(x) {}

    State init() const { return x_.init(); }

    State next(const State& s, const Alphabet& a, size_t i) const {
        return x_.next(s, a, i);
    }

    bool accept(const State& s) const {
        return !x_.accept(s);
    }

    bool successful(const State& s) const {
        return !x_.successful(s);
    }

    bool unsuccessful(const State& s) const {
        return !x_.unsuccessful(s);
    }

   private:
    X x_;
};

template <typename X, typename Y>
class ProdDfa {
   public:
    using Alphabet = pair<typename X::Alphabet, typename Y::Alphabet>;
    using State = pair<typename X::State, typename Y::State>;

    ProdDfa(const X& x, const Y& y) : x_(x), y_(y) {}

    State init() const { return make_pair(x_.init(), y_.init()); }

    State next(const State& s, const Alphabet& a, size_t i) const {
        return make_pair(x_.next(s.first, a.first, i), y_.next(s.second, a.second, i));
    }

    bool accept(const State& s) const {
        return x_.accept(s.first) and y_.accept(s.second);
    }

    bool successful(const State& s) const {
        return x_.successful(s.first) and y_.successful(s.second);
    }

    bool unsuccessful(const State& s) const {
        return x_.unsuccessful(s.first) or y_.unsuccessful(s.second);
    }

   private:
    X x_;
    Y y_;
};

// 0以上N以下の整数を受理するDFA
class Leq {
   public:
    using Alphabet = char;
    using State = Ordering;

    Leq(const string& n) : digits_(n.begin(), n.end()) {}

    State init() const {
        return State::Equal;
    }

    State next(State s, const Alphabet& a, size_t i) const {
        if (s == State::Greater) {
            return State::Greater;
        }

        if (s == State::Less) {
            return State::Less;
        }

        if (a < digits_[i]) {
            return State::Less;
        }

        if (a == digits_[i]) {
            return State::Equal;
        }

        return State::Greater;
    }

    bool accept(State s) const {
        return s != State::Greater;
    }

    bool successful(State s) const {
        return s == State::Less;
    }

    bool unsuccessful(State s) const {
        return s == State::Greater;
    }

   private:
    vector<char> digits_;
};

// 0以上N未満の整数を受理するDFA
class Le {
   public:
    using Alphabet = char;
    using State = Ordering;

    Le(const string& n) : digits_(n.begin(), n.end()) {}

    State init() const {
        return State::Equal;
    }

    State next(State s, const Alphabet& a, size_t i) const {
        if (s == State::Greater) {
            return State::Greater;
        }

        if (s == State::Less) {
            return State::Less;
        }

        if (a < digits_[i]) {
            return State::Less;
        }

        if (a == digits_[i]) {
            return State::Equal;
        }

        return State::Greater;
    }

    bool accept(State s) const {
        return s == State::Less;
    }

    bool successful(State s) const {
        return s == State::Less;
    }

    bool unsuccessful(State s) const {
        return s == State::Greater;
    }

   private:
    vector<char> digits_;
};

// Mの倍数を受理するDFA
class MultipleOf {
   public:
    using Alphabet = char;
    using State = int;

    MultipleOf(int m) : m_(m) {}

    State init() const {
        return 0;
    }

    State next(State s, const Alphabet& a, size_t i) const {
        return (s * 10 + (a - '0')) % m_;
    }

    bool accept(State s) const {
        return s == 0;
    }

    bool successful(State s) const {
        return s == 0;
    }

    bool unsuccessful(State s) const {
        return 0;
    }

   private:
    int m_;
};

class LeadingZero {
   public:
    using Alphabet = char;
    using State = bool;

    LeadingZero() {}

    State init() const {
        return true;
    }

    State next(State s, const Alphabet& a, size_t i) const {
        return s and a == '0';
    }

    bool accept(State s) const {
        return !s;
    }

    bool successful(State s) const {
        return !s;
    }

    bool unsuccessful(State s) const {
        return 0;
    }
};

template <typename DFA>
long long count_dfa(const DFA& dfa, size_t n, const vector<typename DFA::Alphabet>& alphabet) {
    using State = typename DFA::State;
    using S = long long;
    auto op = [](S a, S b) { return (a + b) % 10000; };
    auto e = S(0);

    unordered_map<State, S> dp;
    unordered_map<State, S> dp_next;

    dp.emplace(dfa.init(), 1);

    for (size_t i = 0; i < n; ++i) {
        dp_next.clear();
        for (const auto& [state, count] : dp) {
            for (const auto& a : alphabet) {
                State s1 = dfa.next(state, a, i);
                if (dfa.unsuccessful(s1)) continue;
                dp_next[s1] = (dp_next[s1] + count) % 10000;
            }
        }
        dp.swap(dp_next);
    }

    S res = 0;
    for (const auto& [state, count] : dp) {
        if (dfa.accept(state)) {
            res = op(res, count);
        }
    }

    return res;
}

string decimalToBinary(const string& decimalStr) {
    if (decimalStr.empty()) return "0";
    string num = decimalStr;
    string binaryStr = "";
    while (num != "0") {
        int remainder = 0;
        string quotient = "";
        for (char ch : num) {
            int current = remainder * 10 + (ch - '0');
            if (!quotient.empty() || current / 2 != 0) {
                quotient += (current / 2) + '0';
            }
            remainder = current % 2;
        }
        binaryStr += (remainder ? '1' : '0');
        num = quotient.empty() ? "0" : quotient;
    }

    // 逆順にする
    reverse(binaryStr.begin(), binaryStr.end());
    return binaryStr.empty() ? "0" : binaryStr;
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    vector<char> alphabet = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    string a, b;
    int m;
    in(a, b, m);
    if (a.size() < b.size()) {
        a = string(b.size() - a.size(), '0') + a;
    } else if (a.size() > b.size()) {
        b = string(a.size() - b.size(), '0') + b;
    }
    Dfa dfar = AndDfa(AndDfa(Leq(b), MultipleOf(m)), Zig());
    Dfa dfal = AndDfa(AndDfa(Le(a), MultipleOf(m)), Zig());
    int resr = count_dfa(dfar, b.size(), alphabet);
    int resl = count_dfa(dfal, a.size(), alphabet);
    out((resr - resl + 10000) % 10000);
}
accuracy: 1
time_ms: 1420
memory_kb: 4480
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;

string s;
int n,m;
int dp[502][501][10][2][2];////idx,mod,prev_digit,inc/dec,start digit
int MOD=1e4;

int count(int idx,int rem,int digit,int inc,int f){
    if(idx==n){
        return (!rem);
    }
    if(dp[idx][rem][digit][inc][f]!=-1)return dp[idx][rem][digit][inc][f];
    int ans=0;
    if(inc){
        int limit=9;
        if(!f)limit=s[idx]-'0';
        for(int d=0;d<=limit;d++){
            if(d>digit){
                ans+=count(idx+1,((rem*10)%m+d)%m,d,0,(d==s[idx]-'0')?f:1);
                ans%=MOD;
            }
        }
    }
    else{
        int limit=9;
        if(!f)limit=s[idx]-'0';
        for(int d=0;d<=limit;d++){
            if(d<digit){
                ans+=count(idx+1,((rem*10)%m+d)%m,d,1,(d==s[idx]-'0')?f:1);
                ans%=MOD;
            }
        }
    }
    return dp[idx][rem][digit][inc][f]=ans;

}

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    string a,b;cin>>a>>b;
    cin>>m;
    s=b;
    n=b.length();
    int ans=0;
    memset(dp,-1, sizeof(dp));
    for(int i=0;i<n;i++){
        for(int d=1;d<=9;d++){
            if(!i){
                if(d<=s[0]-'0'){
                    ans+=count(i+1,d%m,d,1,(d==s[0]-'0')?0:1);
                    ans%=MOD;
                    if(i!=n-1)ans+=count(i+1,d%m,d,0,(d==s[0]-'0')?0:1);
                    ans%=MOD;
                }
            }
            else{
                ans+=count(i+1,d%m,d,1,1);
                ans%=MOD;
                if(i!=n-1)ans+=count(i+1,d%m,d,0,1);
                ans%=MOD;
            }
        }
    }
    memset(dp,-1,sizeof (dp));
    n=a.length();
    s=a;
    for(int i=0;i<n;i++){
        for(int d=1;d<=9;d++){
            if(!i){
                if(d<=s[0]-'0'){
                    ans=ans-count(i+1,d%m,d,1,(d==s[0]-'0')?0:1)+MOD;
                    ans%=MOD;
                    if(i!=n-1)ans=ans-count(i+1,d%m,d,0,(d==s[0]-'0')?0:1)+MOD;
                    ans%=MOD;
                }
            }
            else{
                ans=ans-count(i+1,d%m,d,1,1)+MOD;
                ans%=MOD;
                if(i!=n-1)ans=ans-count(i+1,d%m,d,0,1)+MOD;
                ans%=MOD;
            }
        }
    }
    if(n==1){
        if((a[0]-'0')%m==0)ans++;
    }
    else{
        int inc=1;
        if(a[1]>a[0])inc=0;
        int is_zigzag=1;
        int rem=(a[0]-'0');
        rem%=m;

        for (int i = 2; i < n; i++) {
            if(inc && a[i]<=a[i-1])
                is_zigzag=0;
            if(!inc && a[i]>=a[i-1])
                is_zigzag=0;
            rem*=10;
            rem+=(a[i]-'0');
            rem%=m;

        }
        is_zigzag=(is_zigzag & (!rem));
        ans+=is_zigzag;
    }
    cout<<ans%MOD<<endl;



    return 0;
}
accuracy: 1
time_ms: 530
memory_kb: 42536
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vll=vector<ll>;
using vvll=vector<vll>;
using vvvll=vector<vvll>;
using vvvvll=vector<vvvll>;

ll M;

bool is_zigzag(string S){
    ll N=S.size();
    ll m=0;
    for(auto s:S)m=(m*10+s-'0')%M;
    if(m!=0)return 0;
    for(int j=0;j<2;j++){
        bool OK=1;
        for(int i=0;i<N-1;i++){
            if(S[i]==S[i+1])OK=0;
            if(i==N-2)continue;
            if(i%2==j){
                if(S[i]<=S[i+1]||S[i+1]>=S[i+2])OK=0;
            }
            else{
                if(S[i]>=S[i+1]||S[i+1]<=S[i+2])OK=0;
            }
        } 
        if(OK)return 1;
    }
    return 0;
}

ll f(string S){
    ll N=S.size();
    vvvll DP(10,vvll(M,vll(3,0)));
    auto DPJ=DP;
    for(int s=1;s<S[0]-'0';s++){
        DP[s][s%M][0]=1;
    }
    DPJ[S[0]-'0'][(S[0]-'0')%M][0]=1;
    //0未確定, 1: 直前で減少, 2: 直前で増加
    for(int i=1;i<N;i++){
        vvvll NDP(10,vvll(M,vll(3,0)));
        auto NDPJ=NDP;
        for(int n=1;n<10;n++){
            NDP[n][n%M][0]++;//i桁目が先頭
        }
        for(int n=0;n<10;n++){
            for(int d=0;d<10;d++){
                for(int m=0;m<M;m++){
                    if(n==d)continue;
                    int nm=(m*10+d)%M;
                    if(d<S[i]-'0'){
                        if(n>d){
                            NDP[d][nm][1]+=DP[n][m][0]+DPJ[n][m][0];
                            NDP[d][nm][1]+=DP[n][m][2]+DPJ[n][m][2];
                        }
                        else{
                            NDP[d][nm][2]+=DP[n][m][0]+DPJ[n][m][0];
                            NDP[d][nm][2]+=DP[n][m][1]+DPJ[n][m][1];
                        }
                    }
                    else if(d==S[i]-'0'){
                        if(n>d){
                            NDP[d][nm][1]+=DP[n][m][0];
                            NDPJ[d][nm][1]+=DPJ[n][m][0];
                            NDP[d][nm][1]+=DP[n][m][2];
                            NDPJ[d][nm][1]+=DPJ[n][m][2];
                        }
                        else{
                            NDP[d][nm][2]+=DP[n][m][0];
                            NDPJ[d][nm][2]+=DPJ[n][m][0];
                            NDP[d][nm][2]+=DP[n][m][1];
                            NDPJ[d][nm][2]+=DPJ[n][m][1];
                        }
                    }
                    else{
                        if(n>d){
                            NDP[d][nm][1]+=DP[n][m][0];
                            NDP[d][nm][1]+=DP[n][m][2];
                        }
                        else{
                            NDP[d][nm][2]+=DP[n][m][0];
                            NDP[d][nm][2]+=DP[n][m][1];
                        }
                    }
                    for(int k=0;k<3;k++){
                        NDP[d][nm][k]%=10000;
                        NDPJ[d][nm][k]%=10000;
                    }
                }
            }
        }
        swap(DP,NDP);
        swap(DPJ,NDPJ);
    }
    ll res=0;
    for(int d=0;d<10;d++){
        for(int k=0;k<3;k++){
            res+=DP[d][0][k]+DPJ[d][0][k];
        }
    }
    return res%10000;

}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    string A,B;
    cin>>A>>B>>M;
    ll an=f(B)-f(A);
    if(is_zigzag(A))an++;
    cout<<(an+10000)%10000<<endl;
}
accuracy: 1
time_ms: 1000
memory_kb: 4460
final_rank: 12

code_snippet: #line 1 "lib/mod/modint.hpp"



#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#line 1 "lib/atcoder/internal_math.hpp"



#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#line 1 "lib/atcoder/internal_type_traits.hpp"



#line 7 "lib/atcoder/internal_type_traits.hpp"

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


#line 14 "lib/mod/modint.hpp"

namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static constexpr mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    constexpr static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        _v = (unsigned int)(v % umod());
    }

    constexpr unsigned int val() const { return _v; }

    constexpr mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    constexpr mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    constexpr mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    constexpr mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    constexpr mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    constexpr mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    constexpr mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    constexpr mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    constexpr mint operator+() const { return *this; }
    constexpr mint operator-() const { return mint() - *this; }

    constexpr mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    constexpr mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    constexpr friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    constexpr friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    constexpr friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    constexpr friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    constexpr friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    constexpr friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#line 2 "main.cpp"
using mint = atcoder::static_modint<10000>;
#line 2 "lib/prelude.hpp"
#ifndef LOCAL
#pragma GCC optimize("O3")
// #pragma GCC target("avx2")
#endif
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep2(i, m, n) for (auto i = (m); i < (n); i++)
#define rep(i, n) rep2(i, 0, n)
#define repr2(i, m, n) for (auto i = (n); i-- > (m);)
#define repr(i, n) repr2(i, 0, n)
#define all(x) begin(x), end(x)
template <class T> auto ndvec(int n, T e) { return vector(n, e); }
template <class... Ts> auto ndvec(int n, Ts... e) { return vector(n, ndvec(e...)); }
#line 3 "lib/util/seed.hpp"

auto seed() {
#if defined(LOCAL) || defined(FIX_SEED)
  return 314169265258979;
#endif
  return chrono::steady_clock::now().time_since_epoch().count();
}
#line 3 "lib/util/rand.hpp"

uint32_t rand32() {
  static uint32_t x = seed();
  x ^= x << 13;
  x ^= x >> 17;
  x ^= x << 5;
  return x;
}

uint64_t rand64() {
  return uint64_t(rand32()) << 32 | rand32();
}
#line 3 "lib/util/hash.hpp"

[[gnu::const]] uint64_t splitmix64(uint64_t x) {
  // http://xorshift.di.unimi.it/splitmix64.c
  x += 0x9e3779b97f4a7c15;
  x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
  x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
  return x ^ (x >> 31);
}

template <class T, class = void>
struct anti_hack_hash;

template <class T>
struct anti_hack_hash<T, enable_if_t<is_convertible_v<T, uint64_t>>> {
  size_t operator()(T x) const {
    static const uint64_t ofs = seed();
    return splitmix64((uint64_t)x + ofs);
  }
};

template <class T>
struct anti_hack_hash<T, void_t<decltype(tuple_size<T>::value)>> {
  size_t operator()(const T& x) const {
    return hash_impl(x, make_index_sequence<tuple_size_v<T>>{});
  }

 private:
  static auto make_seed() {
    array<uint64_t, tuple_size_v<T>> res;
    res[0] = seed();
    rep(i, tuple_size_v<T> - 1) res[i + 1] = splitmix64(res[i]) + seed();
    return res;
  }
  template <size_t... Is>
  static size_t hash_impl(const T& x, index_sequence<Is...>) {
    size_t res = 0;
    ((void)(res = splitmix64(
                res + anti_hack_hash<tuple_element_t<Is, T>>{}(get<Is>(x)))),
     ...);
    return res;
  }
};
#line 4 "lib/ds/hash_map.hpp"
#include <ext/pb_ds/assoc_container.hpp>

template <class K, class V, class Hash = anti_hack_hash<K>>
using hash_map = __gnu_pbds::gp_hash_table<K, V, Hash>;
#line 4 "lib/dfa.hpp"

namespace dfa {

struct dfa_default {
  using alphabet = char;
  template <class T>
  bool successful(T &&) const {
    return false;
  }
  template <class T>
  bool unsuccessful(T &&) const {
    return false;
  }
};

struct leq_lt_base {
  const char *p;
  leq_lt_base(const char *p) : p(p) {}

  using alphabet = char;
  using state = signed char;
  state init() const { return 0; }
  state next(state s, alphabet a, int i) const {
    return s ? s : (a > p[i]) - (a < p[i]);
  }
  bool successful(state s) const { return s == -1; }
  bool unsuccessful(state s) const { return s == 1; }
};

struct leq : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s != 1; }
};

struct lt : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s == -1; }
};

template <class X>
struct lnot : X {
  using X::X;
  bool accept(typename lnot::state s) const { return !X::accept(s); }
  bool successful(typename lnot::state s) const { return X::unsuccessful(s); }
  bool unsuccessful(typename lnot::state s) const { return X::successful(s); }
};

template <class X, class... Xs>
struct land {
  tuple<X, Xs...> xs;
  land(X x, Xs... xs_) : xs(move(x), move(xs_)...) {}

  static_assert((is_same_v<typename X::alphabet, typename Xs::alphabet> &&
                 ... && true));
  using alphabet = typename X::alphabet;
  using state = tuple<typename X::state, typename Xs::state...>;
  state init() const { return init(make_index_sequence<1 + sizeof...(Xs)>{}); }
  template <size_t... Is>
  state init(index_sequence<Is...>) const {
    return tuple(get<Is>(xs).init()...);
  }
  state next(state s, alphabet a, int i) const {
    return next(s, a, i, make_index_sequence<1 + sizeof...(Xs)>{});
  }
  template <size_t... Is>
  state next(state s, alphabet a, int i, index_sequence<Is...>) const {
    return tuple(get<Is>(xs).next(get<Is>(s), a, i)...);
  }
  bool accept(state s) const {
    return accept(s, make_index_sequence<1 + sizeof...(Xs)>{});
  }
  template <size_t... Is>
  bool accept(state s, index_sequence<Is...>) const {
    return (get<Is>(xs).accept(get<Is>(s)) && ... && true);
  }
  bool successful(state s) const {
    return successful(s, make_index_sequence<1 + sizeof...(Xs)>{});
  }
  template <size_t... Is>
  bool successful(state s, index_sequence<Is...>) const {
    return (get<Is>(xs).successful(get<Is>(s)) && ... && true);
  }
  bool unsuccessful(state s) const {
    return unsuccessful(s, make_index_sequence<1 + sizeof...(Xs)>{});
  }
  template <size_t... Is>
  bool unsuccessful(state s, index_sequence<Is...>) const {
    return (get<Is>(xs).unsuccessful(get<Is>(s)) || ... || false);
  }
};

const string digits = "0123456789";

template <class T, class X, class Iter = string::const_iterator>
T count(const X &dfa, int n, Iter alphabets_f = begin(digits),
        Iter alphabets_l = end(digits)) {
  hash_map<typename X::state, T> prv, nxt;
  // map<typename X::state, T> prv, nxt;
  nxt[dfa.init()] = T(1);
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) nxt[s2] += k;
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt)
    if (dfa.accept(s)) ans += k;
  return ans;
}

template <class T, class X, class Iter = string::const_iterator>
T sum(const X &dfa, int n, Iter alphabets_f = begin(digits),
      Iter alphabets_l = end(digits)) {
  hash_map<typename X::state, pair<T, T>> prv, nxt;
  nxt[dfa.init()] = pair(T(0), T(1));
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) {
          nxt[s2].first += k.first * 10 + (*p - '0') * k.second;
          nxt[s2].second += k.second;
        }
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt)
    if (dfa.accept(s)) ans += k.first;
  return ans;
}

}  // namespace dfa
#line 3 "lib/dfa/multiple_of.hpp"

namespace dfa {

template <class T>
struct multiple_of : dfa_default {
  T d;
  constexpr multiple_of(T d) : d(d) {}

  using alphabet = char;
  using state = T;
  state init() const { return 0; }
  state next(state s, alphabet a, int) const {
    return (s * 10 + (a - '0')) % d;
  }
  bool accept(state s) const { return s == 0; }
};

}  // namespace dfa
#line 3 "lib/io.hpp"

struct int1 {
  int val; int1(int a = 1) : val(a - 1) {}
  operator int() const { return val; }
};

template <size_t BufSize = 1 << 26> class stdin_reader {
 public: stdin_reader() { buf[fread_unlocked(buf, 1, sizeof(buf), stdin)] = 0; } template <class T> enable_if_t<is_integral_v<T>> read(T& x) { skip(); [[maybe_unused]] bool neg = false; if constexpr (is_signed_v<T>) neg = *p == '-' ? (p++, true) : false; x = 0; while (*p > ' ') x = x * 10 + (*p++ & 0x0F); if constexpr (is_signed_v<T>) x = neg ? -x : x; } template <class T> void_t<decltype(&T::val)> read(T& x) { x = T((unsigned)(*this)); } void read(char*& q) { skip(); q = p; while (*p > ' ') p++; *p = 0; } template <size_t N> void read(char (&s)[N]) { read(s); } void read(string& s) { skip(); char* p0 = p; while (*p > ' ') p++; s.assign(p0, p); } template <class T, void_t<decltype(tuple_size<T>::value)>* = nullptr> void read(T& x) { read_tuple_impl(x, make_index_sequence<tuple_size_v<T>>{}); } template <class T, class U> void read(pair<T, U>& x) { read(x.first), read(x.second); } template <class T, size_t N> void read(T (&a)[N]) { for (auto& e : a) read(e); } template <class T> operator T() { T x; return read(x), x; } template <class... Ts> void operator()(Ts&... xs) { (read(xs), ...); } int operator--() { return (int)*this - 1; } template <class T> T* arr(int n) { T* p = new T[n + 1]; rep(i, n) read(p[i]); return p; } template <class T> void vec(vector<T>& v, int n) { v.resize(n); for (auto& e : v) read(e); } template <class T> vector<T> vec(int n) { vector<T> v; return vec(v, n), v; } template <class... Ts> tuple<vector<Ts>...> vecs(int n) { tuple<vector<Ts>...> res; vecs_impl(res, n, make_index_sequence<sizeof...(Ts)>{}); return res; } template <class T> void vvec(vector<vector<T>>& v, int n, int m) { v.resize(n); for (auto& e : v) vec(e, m); } template <class T> vector<vector<T>> vvec(int n, int m) { vector<vector<T>> v; return vvec(v, n, m), v; } template <class... Ts> auto cols(int n) { return transpose(vec<tuple<Ts...>>(n)); } private: char buf[BufSize], *p = buf; void skip() { while (*p <= ' ') p++; } template <class T, size_t... Is> void read_tuple_impl(T& x, index_sequence<Is...>) { (*this)(get<Is>(x)...); } template <class T, size_t... Is> void vecs_impl(T& x, int n, index_sequence<Is...>) { (vec(get<Is>(x), n), ...); } template <class T, size_t... Is> static auto transpose_impl(const vector<T>& v, index_sequence<Is...>) { tuple<vector<decay_t<tuple_element_t<Is, T>>>...> w; (get<Is>(w).reserve(v.size()), ...); for (const auto& row : v) (get<Is>(w).push_back(get<Is>(row)), ...); return w; } template <class T> static auto transpose(const vector<T>& v) { return transpose_impl(v, make_index_sequence<tuple_size_v<T>>{}); }
};
template <size_t BufSize = 1 << 26> class stdout_writer {
 public: ~stdout_writer() { flush(); } void flush() { fwrite_unlocked(buf, 1, p - buf, stdout), p = buf; } void write_char(char c) { *p++ = c; } void write() {} void write(char c) { write_char(c); } template <class T> enable_if_t<is_integral_v<T>> write(T x) { if (!x) return write_char('0'); if constexpr (is_signed_v<T>) if (x < 0) write_char('-'), x = -x; static char tmp[16]; char* q = end(tmp); while (x >= 10000) memcpy(q -= 4, digits.data + x % 10000 * 4, 4), x /= 10000; if (x < 10) write_char('0' + x); else if (x < 100) write_char('0' + (uint8_t)x / 10), write_char('0' + (uint8_t)x % 10); else if (x < 1000) memcpy(p, digits.data + x * 4 + 1, 3), p += 3; else memcpy(p, digits.data + x * 4, 4), p += 4; memcpy(p, q, end(tmp) - q), p += end(tmp) - q; } template <class T> void_t<decltype(&T::val)> write(T x) { write(x.val()); } void write(double x) { static char tmp[40]; sprintf(tmp, "%.15f", x); write(tmp); } void write(const char* s) { while (*s) *p++ = *s++; } void write(const string& s) { memcpy(p, s.c_str(), s.size()), p += s.size(); } template <class T, class U> void write(const pair<T, U>& x) { write(x.first), write_char(' '), write(x.second); } template <class... Ts> void write(const tuple<Ts...>& x) { write_tuple(x, make_index_sequence<sizeof...(Ts)>{}); } template <class... Ts> void write(const Ts&... xs) { ((write(xs), write_char(' ')), ...), --p; } template <class... Ts> void writeln(const Ts&... xs) { write(xs...), write_char('\n'); } template <class... Ts> void operator()(const Ts&... xs) { writeln(xs...); } template <class It> void iter(It first, It last, char sep = ' ') { if (first == last) write_char('\n'); else { while (first != last) write(*first++), write_char(sep); p[-1] = '\n'; } } void del() { *--p = 0; } void Yes(bool b = true) { writeln(b ? "Yes" : "No"); } void YES(bool b = true) { writeln(b ? "YES" : "NO"); } void Takahashi(bool b = true) { writeln(b ? "Takahashi" : "Aoki"); } private: char buf[BufSize], *p = buf; template <class T, size_t... Is> void write_tuple(const T& x, index_sequence<Is...>) { ((write(get<Is>(x)), write_char(' ')), ...), --p; } struct four_digits { char data[40000]; constexpr four_digits() : data() { for (int i = 0; i < 10000; i++) for (int n = i, j = 4; j--;) data[i * 4 + j] = n % 10 + '0', n /= 10; } } static constexpr digits{}; public:
#define INSTANT(s) void s() { writeln(#s); }
  INSTANT(No) INSTANT(NO) INSTANT(Aoki) INSTANT(possible) INSTANT(Possible) INSTANT(POSSIBLE) INSTANT(impossible) INSTANT(Impossible) INSTANT(IMPOSSIBLE)
#undef INSTANT
};
stdin_reader<> in;
stdout_writer<> out;
#line 5 "main.cpp"

enum zig_state {
  INC,
  DEC,
  ZERO,
  INIT,
  FAIL,
};

struct zig_zag : dfa::dfa_default {
  using state = pair<char, zig_state>;
  state init() const { return state('0', ZERO); }
  state next(state s, char c, int) const {
    switch (s.second) {
      case FAIL:
        return s;
      case ZERO:
        if (c == '0')
          return s;
        else
          return state(c, INIT);
      case INIT:
        return state(c, s.first < c ? INC : s.first > c ? DEC : FAIL);
      case INC:
        return state(c, s.first > c ? DEC : FAIL);
      case DEC:
        return state(c, s.first < c ? INC : FAIL);
    }
    assert(false);
  }
  bool accept(state s) const { return s.second != FAIL; }
  bool unsuccessful(state s) const { return s.second == FAIL; }
};

int main() {
  string A = in, B = in;
  int n = B.size();
  A.insert(0, n - A.size(), '0');
  int M = in;
  auto dfa = dfa::land(zig_zag(), dfa::multiple_of(M), dfa::leq(B.c_str()),
                       dfa::lnot<dfa::lt>(A.c_str()));
  mint ans = dfa::count<mint>(dfa, B.size());
  out(ans.val());
}
accuracy: 1
time_ms: 1090
memory_kb: 7736
final_rank: 15

code_snippet: #line 1 "lib/mod/modint.hpp"



#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#line 1 "lib/atcoder/internal_math.hpp"



#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#line 1 "lib/atcoder/internal_type_traits.hpp"



#line 7 "lib/atcoder/internal_type_traits.hpp"

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


#line 14 "lib/mod/modint.hpp"

namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static constexpr mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    constexpr static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        _v = (unsigned int)(v % umod());
    }

    constexpr unsigned int val() const { return _v; }

    constexpr mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    constexpr mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    constexpr mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    constexpr mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    constexpr mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    constexpr mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    constexpr mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    constexpr mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    constexpr mint operator+() const { return *this; }
    constexpr mint operator-() const { return mint() - *this; }

    constexpr mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    constexpr mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    constexpr friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    constexpr friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    constexpr friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    constexpr friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    constexpr friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    constexpr friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#line 2 "main.cpp"
using mint = atcoder::static_modint<10000>;
#line 2 "lib/prelude.hpp"
#ifndef LOCAL
#pragma GCC optimize("O3")
// #pragma GCC target("avx2")
#endif
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep2(i, m, n) for (auto i = (m); i < (n); i++)
#define rep(i, n) rep2(i, 0, n)
#define repr2(i, m, n) for (auto i = (n); i-- > (m);)
#define repr(i, n) repr2(i, 0, n)
#define all(x) begin(x), end(x)
template <class T> auto ndvec(int n, T e) { return vector(n, e); }
template <class... Ts> auto ndvec(int n, Ts... e) { return vector(n, ndvec(e...)); }
#line 3 "lib/util/seed.hpp"

auto seed() {
#if defined(LOCAL) || defined(FIX_SEED)
  return 314169265258979;
#endif
  return chrono::steady_clock::now().time_since_epoch().count();
}
#line 3 "lib/util/rand.hpp"

uint32_t rand32() {
  static uint32_t x = seed();
  x ^= x << 13;
  x ^= x >> 17;
  x ^= x << 5;
  return x;
}

uint64_t rand64() {
  return uint64_t(rand32()) << 32 | rand32();
}
#line 3 "lib/util/hash.hpp"

template <class T, class = void>
struct simple_hash : hash<T> {};

template <class T>
struct simple_hash<T, void_t<decltype(tuple_size<T>::value)>> {
  size_t operator()(const T& x) const {
    return hash_impl(x, make_index_sequence<tuple_size_v<T>>{});
  }

 private:
  template <size_t... Is>
  static size_t hash_impl(const T& x, index_sequence<Is...>) {
    size_t res = 0;
    ((void)(res ^= (res << 6) + (res >> 2) + 0x9e3779b9 +
                   simple_hash<tuple_element_t<Is, T>>{}(get<Is>(x))),
     ...);
    return res;
  }
};

uint64_t splitmix64(uint64_t x) {
  // http://xorshift.di.unimi.it/splitmix64.c
  x += 0x9e3779b97f4a7c15;
  x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
  x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
  return x ^ (x >> 31);
}

template <class T, class = void>
struct anti_hack_hash;

template <class T>
struct anti_hack_hash<T, enable_if_t<is_convertible_v<T, uint64_t>>> {
  size_t operator()(T x) const {
    static const uint64_t ofs = seed();
    return splitmix64((uint64_t)x + ofs);
  }
};

template <class T>
struct anti_hack_hash<T, void_t<decltype(tuple_size<T>::value)>> {
  size_t operator()(const T& x) const {
    return hash_impl(x, make_index_sequence<tuple_size_v<T>>{});
  }

 private:
  static auto make_seed() {
    array<uint64_t, tuple_size_v<T>> res;
    res[0] = seed();
    rep(i, tuple_size_v<T> - 1) res[i + 1] = splitmix64(res[i]) + seed();
    return res;
  }
  template <size_t... Is>
  static size_t hash_impl(const T& x, index_sequence<Is...>) {
    size_t res = 0;
    ((void)(res = splitmix64(
                res + anti_hack_hash<tuple_element_t<Is, T>>{}(get<Is>(x)))),
     ...);
    return res;
  }
};
#line 4 "lib/ds/hash_map.hpp"
#include <ext/pb_ds/assoc_container.hpp>

template <class K, class V, class Hash = simple_hash<K>>
using hash_map = __gnu_pbds::gp_hash_table<K, V, Hash>;
#line 4 "lib/dfa.hpp"

namespace dfa {

struct dfa_default {
  using alphabet = char;
  template <class T>
  bool successful(T &&) const {
    return false;
  }
  template <class T>
  bool unsuccessful(T &&) const {
    return false;
  }
};

struct leq_lt_base {
  const char *p;
  leq_lt_base(const char *p) : p(p) {}

  using alphabet = char;
  using state = signed char;
  state init() const { return 0; }
  state next(state s, alphabet a, int i) const {
    return s ? s : (a > p[i]) - (a < p[i]);
  }
  bool successful(state s) const { return s == -1; }
  bool unsuccessful(state s) const { return s == 1; }
};

struct leq : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s != 1; }
};

struct lt : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s == -1; }
};

template <class X>
struct lnot : X {
  using X::X;
  bool accept(typename lnot::state s) const { return !X::accept(s); }
  bool successful(typename lnot::state s) const { return X::unsuccessful(s); }
  bool unsuccessful(typename lnot::state s) const { return X::successful(s); }
};

template <class X, class Y>
struct land {
  X x;
  Y y;
  land(X x, Y y) : x(x), y(y) {}

  static_assert(is_same_v<typename X::alphabet, typename Y::alphabet>);
  using alphabet = typename X::alphabet;
  using state = pair<typename X::state, typename Y::state>;
  state init() const { return make_pair(x.init(), y.init()); }
  state next(state s, alphabet a, int i) const {
    return make_pair(x.next(s.first, a, i), y.next(s.second, a, i));
  }
  bool accept(state s) const {
    return x.accept(s.first) && y.accept(s.second);
  }
  bool successful(state s) const {
    return x.successful(s.first) && y.successful(s.second);
  }
  bool unsuccessful(state s) const {
    return x.unsuccessful(s.first) || y.unsuccessful(s.second);
  }
};

const string digits = "0123456789";

template <class T, class X, class Iter = string::const_iterator>
T count(const X &dfa, int n, Iter alphabets_f = begin(digits),
        Iter alphabets_l = end(digits)) {
  hash_map<typename X::state, T> prv, nxt;
  // map<typename X::state, T> prv, nxt;
  nxt[dfa.init()] = T(1);
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) nxt[s2] += k;
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt) if (dfa.accept(s)) ans += k;
  return ans;
}

template <class T, class X, class Iter = string::const_iterator>
T sum(const X &dfa, int n, Iter alphabets_f = begin(digits),
        Iter alphabets_l = end(digits)) {
  hash_map<typename X::state, pair<T, T>, simple_hash<typename X::state>> prv, nxt;
  nxt[dfa.init()] = pair(T(0), T(1));
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) {
          nxt[s2].first += k.first * 10 + (*p-'0') * k.second;
          nxt[s2].second += k.second;
        }
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt) if (dfa.accept(s)) ans += k.first;
  return ans;
}

}  // namespace dfa
#line 3 "lib/dfa/multiple_of.hpp"

namespace dfa {

template <class T>
struct multiple_of : dfa_default {
  T d;
  constexpr multiple_of(T d) : d(d) {}

  using alphabet = char;
  using state = T;
  state init() const { return 0; }
  state next(state s, alphabet a, int) const {
    return (s * 10 + (a - '0')) % d;
  }
  bool accept(state s) const { return s == 0; }
};

}  // namespace dfa
#line 3 "lib/io.hpp"

struct int1 {
  int val; int1(int a = 1) : val(a - 1) {}
  operator int() const { return val; }
};

template <size_t BufSize = 1 << 26> class stdin_reader {
 public: stdin_reader() { buf[fread_unlocked(buf, 1, sizeof(buf), stdin)] = 0; } template <class T> enable_if_t<is_integral_v<T>> read(T& x) { skip(); [[maybe_unused]] bool neg = false; if constexpr (is_signed_v<T>) neg = *p == '-' ? (p++, true) : false; x = 0; while (*p > ' ') x = x * 10 + (*p++ & 0x0F); if constexpr (is_signed_v<T>) x = neg ? -x : x; } template <class T> void_t<decltype(&T::val)> read(T& x) { x = T((unsigned)(*this)); } void read(char*& q) { skip(); q = p; while (*p > ' ') p++; *p = 0; } template <size_t N> void read(char (&s)[N]) { read(s); } void read(string& s) { skip(); char* p0 = p; while (*p > ' ') p++; s.assign(p0, p); } template <class T, void_t<decltype(tuple_size<T>::value)>* = nullptr> void read(T& x) { read_tuple_impl(x, make_index_sequence<tuple_size_v<T>>{}); } template <class T, class U> void read(pair<T, U>& x) { read(x.first), read(x.second); } template <class T, size_t N> void read(T (&a)[N]) { for (auto& e : a) read(e); } template <class T> operator T() { T x; return read(x), x; } template <class... Ts> void operator()(Ts&... xs) { (read(xs), ...); } int operator--() { return (int)*this - 1; } template <class T> T* arr(int n) { T* p = new T[n + 1]; rep(i, n) read(p[i]); return p; } template <class T> void vec(vector<T>& v, int n) { v.resize(n); for (auto& e : v) read(e); } template <class T> vector<T> vec(int n) { vector<T> v; return vec(v, n), v; } template <class... Ts> tuple<vector<Ts>...> vecs(int n) { tuple<vector<Ts>...> res; vecs_impl(res, n, make_index_sequence<sizeof...(Ts)>{}); return res; } template <class T> void vvec(vector<vector<T>>& v, int n, int m) { v.resize(n); for (auto& e : v) vec(e, m); } template <class T> vector<vector<T>> vvec(int n, int m) { vector<vector<T>> v; return vvec(v, n, m), v; } template <class... Ts> auto cols(int n) { return transpose(vec<tuple<Ts...>>(n)); } private: char buf[BufSize], *p = buf; void skip() { while (*p <= ' ') p++; } template <class T, size_t... Is> void read_tuple_impl(T& x, index_sequence<Is...>) { (*this)(get<Is>(x)...); } template <class T, size_t... Is> void vecs_impl(T& x, int n, index_sequence<Is...>) { (vec(get<Is>(x), n), ...); } template <class T, size_t... Is> static auto transpose_impl(const vector<T>& v, index_sequence<Is...>) { tuple<vector<decay_t<tuple_element_t<Is, T>>>...> w; (get<Is>(w).reserve(v.size()), ...); for (const auto& row : v) (get<Is>(w).push_back(get<Is>(row)), ...); return w; } template <class T> static auto transpose(const vector<T>& v) { return transpose_impl(v, make_index_sequence<tuple_size_v<T>>{}); }
};
template <size_t BufSize = 1 << 26> class stdout_writer {
 public: ~stdout_writer() { flush(); } void flush() { fwrite_unlocked(buf, 1, p - buf, stdout), p = buf; } void write_char(char c) { *p++ = c; } void write() {} void write(char c) { write_char(c); } template <class T> enable_if_t<is_integral_v<T>> write(T x) { if (!x) return write_char('0'); if constexpr (is_signed_v<T>) if (x < 0) write_char('-'), x = -x; static char tmp[16]; char* q = end(tmp); while (x >= 10000) memcpy(q -= 4, digits.data + x % 10000 * 4, 4), x /= 10000; if (x < 10) write_char('0' + x); else if (x < 100) write_char('0' + (uint8_t)x / 10), write_char('0' + (uint8_t)x % 10); else if (x < 1000) memcpy(p, digits.data + x * 4 + 1, 3), p += 3; else memcpy(p, digits.data + x * 4, 4), p += 4; memcpy(p, q, end(tmp) - q), p += end(tmp) - q; } template <class T> void_t<decltype(&T::val)> write(T x) { write(x.val()); } void write(double x) { static char tmp[40]; sprintf(tmp, "%.15f", x); write(tmp); } void write(const char* s) { while (*s) *p++ = *s++; } void write(const string& s) { memcpy(p, s.c_str(), s.size()), p += s.size(); } template <class T, class U> void write(const pair<T, U>& x) { write(x.first), write_char(' '), write(x.second); } template <class... Ts> void write(const tuple<Ts...>& x) { write_tuple(x, make_index_sequence<sizeof...(Ts)>{}); } template <class... Ts> void write(const Ts&... xs) { ((write(xs), write_char(' ')), ...), --p; } template <class... Ts> void writeln(const Ts&... xs) { write(xs...), write_char('\n'); } template <class... Ts> void operator()(const Ts&... xs) { writeln(xs...); } template <class It> void iter(It first, It last, char sep = ' ') { if (first == last) write_char('\n'); else { while (first != last) write(*first++), write_char(sep); p[-1] = '\n'; } } void del() { *--p = 0; } void Yes(bool b = true) { writeln(b ? "Yes" : "No"); } void YES(bool b = true) { writeln(b ? "YES" : "NO"); } void Takahashi(bool b = true) { writeln(b ? "Takahashi" : "Aoki"); } private: char buf[BufSize], *p = buf; template <class T, size_t... Is> void write_tuple(const T& x, index_sequence<Is...>) { ((write(get<Is>(x)), write_char(' ')), ...), --p; } struct four_digits { char data[40000]; constexpr four_digits() : data() { for (int i = 0; i < 10000; i++) for (int n = i, j = 4; j--;) data[i * 4 + j] = n % 10 + '0', n /= 10; } } static constexpr digits{}; public:
#define INSTANT(s) void s() { writeln(#s); }
  INSTANT(No) INSTANT(NO) INSTANT(Aoki) INSTANT(possible) INSTANT(Possible) INSTANT(POSSIBLE) INSTANT(impossible) INSTANT(Impossible) INSTANT(IMPOSSIBLE)
#undef INSTANT
};
stdin_reader<> in;
stdout_writer<> out;
#line 5 "main.cpp"

enum zig_state {
  INC,
  DEC,
  ZERO,
  INIT,
  FAIL,
};

struct zig_zag : dfa::dfa_default {
  using state = pair<char, zig_state>;
  state init() const { return state('0', ZERO); }
  state next(state s, char c, int i) const {
    switch (s.second) {
      case FAIL:
        return s;
      case ZERO:
        if (c == '0')
          return s;
        else
          return state(c, INIT);
      case INIT:
        return state(c, s.first < c ? INC : s.first > c ? DEC : FAIL);
      case INC:
        return state(c, s.first > c ? DEC : FAIL);
      case DEC:
        return state(c, s.first < c ? INC : FAIL);
    }
    assert(false);
  }
  bool accept(state s) const { return s.second != FAIL; }
  bool unsuccessful(state s) const { return s.second == FAIL; }
};

int main() {
  string A = in, B = in;
  int n = B.size();
  A.insert(0, n - A.size(), '0');
  int M = in;
  auto dfa = dfa::land(zig_zag(),
                       dfa::land(dfa::multiple_of(M),
                                 dfa::land(dfa::leq(B.c_str()),
                                           dfa::lnot<dfa::lt>(A.c_str()))));
  mint ans = dfa::count<mint>(dfa, B.size());
  out(ans.val());
}
accuracy: 1
time_ms: 770
memory_kb: 7724
final_rank: 9

code_snippet: #line 1 "lib/mod/modint.hpp"



#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#line 1 "lib/atcoder/internal_math.hpp"



#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#line 1 "lib/atcoder/internal_type_traits.hpp"



#line 7 "lib/atcoder/internal_type_traits.hpp"

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


#line 14 "lib/mod/modint.hpp"

namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static constexpr mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    constexpr static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        _v = (unsigned int)(v % umod());
    }

    constexpr unsigned int val() const { return _v; }

    constexpr mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    constexpr mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    constexpr mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    constexpr mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    constexpr mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    constexpr mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    constexpr mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    constexpr mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    constexpr mint operator+() const { return *this; }
    constexpr mint operator-() const { return mint() - *this; }

    constexpr mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    constexpr mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    constexpr friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    constexpr friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    constexpr friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    constexpr friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    constexpr friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    constexpr friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#line 2 "main.cpp"
using mint = atcoder::static_modint<10000>;
#line 2 "lib/prelude.hpp"
#ifndef LOCAL
#pragma GCC optimize("O3")
// #pragma GCC target("avx2")
#endif
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep2(i, m, n) for (auto i = (m); i < (n); i++)
#define rep(i, n) rep2(i, 0, n)
#define repr2(i, m, n) for (auto i = (n); i-- > (m);)
#define repr(i, n) repr2(i, 0, n)
#define all(x) begin(x), end(x)
template <class T> auto ndvec(int n, T e) { return vector(n, e); }
template <class... Ts> auto ndvec(int n, Ts... e) { return vector(n, ndvec(e...)); }
#line 3 "lib/util/seed.hpp"

auto seed() {
#if defined(LOCAL) || defined(FIX_SEED)
  return 314169265258979;
#endif
  return chrono::steady_clock::now().time_since_epoch().count();
}
#line 3 "lib/util/rand.hpp"

uint32_t rand32() {
  static uint32_t x = seed();
  x ^= x << 13;
  x ^= x >> 17;
  x ^= x << 5;
  return x;
}

uint64_t rand64() {
  return uint64_t(rand32()) << 32 | rand32();
}
#line 3 "lib/util/hash.hpp"

template <class T, class = void>
struct simple_hash : hash<T> {};

template <class T>
struct simple_hash<T, void_t<decltype(tuple_size<T>::value)>> {
  size_t operator()(const T& x) const {
    return hash_impl(x, make_index_sequence<tuple_size_v<T>>{});
  }

 private:
  template <size_t... Is>
  static size_t hash_impl(const T& x, index_sequence<Is...>) {
    size_t res = 0;
    ((void)(res ^=
            (res << 16) ^ simple_hash<tuple_element_t<Is, T>>{}(get<Is>(x))),
     ...);
    return res;
  }
};

uint64_t splitmix64(uint64_t x) {
  // http://xorshift.di.unimi.it/splitmix64.c
  x += 0x9e3779b97f4a7c15;
  x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
  x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
  return x ^ (x >> 31);
}

template <class T, class = void>
struct anti_hack_hash;

template <class T>
struct anti_hack_hash<T, enable_if_t<is_convertible_v<T, uint64_t>>> {
  size_t operator()(T x) const {
    static const uint64_t ofs = seed();
    return splitmix64((uint64_t)x + ofs);
  }
};

template <class T>
struct anti_hack_hash<T, void_t<decltype(tuple_size<T>::value)>> {
  size_t operator()(const T& x) const {
    return hash_impl(x, make_index_sequence<tuple_size_v<T>>{});
  }

 private:
  static auto make_seed() {
    array<uint64_t, tuple_size_v<T>> res;
    res[0] = seed();
    rep(i, tuple_size_v<T> - 1) res[i + 1] = splitmix64(res[i]) + seed();
    return res;
  }
  template <size_t... Is>
  static size_t hash_impl(const T& x, index_sequence<Is...>) {
    size_t res = 0;
    ((void)(res = splitmix64(
                res + anti_hack_hash<tuple_element_t<Is, T>>{}(get<Is>(x)))),
     ...);
    return res;
  }
};
#line 4 "lib/ds/hash_map.hpp"
#include <ext/pb_ds/assoc_container.hpp>

template <class K, class V, class Hash = anti_hack_hash<K>>
using hash_map = __gnu_pbds::gp_hash_table<K, V, Hash>;
#line 4 "lib/dfa.hpp"

namespace dfa {

struct dfa_default {
  using alphabet = char;
  template <class T>
  bool successful(T &&) const {
    return false;
  }
  template <class T>
  bool unsuccessful(T &&) const {
    return false;
  }
};

struct leq_lt_base {
  const char *p;
  leq_lt_base(const char *p) : p(p) {}

  using alphabet = char;
  using state = signed char;
  state init() const { return 0; }
  state next(state s, alphabet a, int i) const {
    return s ? s : (a > p[i]) - (a < p[i]);
  }
  bool successful(state s) const { return s == -1; }
  bool unsuccessful(state s) const { return s == 1; }
};

struct leq : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s != 1; }
};

struct lt : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s == -1; }
};

template <class X>
struct lnot : X {
  using X::X;
  bool accept(typename lnot::state s) const { return !X::accept(s); }
  bool successful(typename lnot::state s) const { return X::unsuccessful(s); }
  bool unsuccessful(typename lnot::state s) const { return X::successful(s); }
};

template <class X, class Y>
struct land {
  X x;
  Y y;
  land(X x, Y y) : x(x), y(y) {}

  static_assert(is_same_v<typename X::alphabet, typename Y::alphabet>);
  using alphabet = typename X::alphabet;
  using state = pair<typename X::state, typename Y::state>;
  state init() const { return make_pair(x.init(), y.init()); }
  state next(state s, alphabet a, int i) const {
    return make_pair(x.next(s.first, a, i), y.next(s.second, a, i));
  }
  bool accept(state s) const {
    return x.accept(s.first) && y.accept(s.second);
  }
  bool successful(state s) const {
    return x.successful(s.first) && y.successful(s.second);
  }
  bool unsuccessful(state s) const {
    return x.unsuccessful(s.first) || y.unsuccessful(s.second);
  }
};

const string digits = "0123456789";

template <class T, class X, class Iter = string::const_iterator>
T count(const X &dfa, int n, Iter alphabets_f = begin(digits),
        Iter alphabets_l = end(digits)) {
  hash_map<typename X::state, T> prv, nxt;
  // map<typename X::state, T> prv, nxt;
  nxt[dfa.init()] = T(1);
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) nxt[s2] += k;
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt) if (dfa.accept(s)) ans += k;
  return ans;
}

template <class T, class X, class Iter = string::const_iterator>
T sum(const X &dfa, int n, Iter alphabets_f = begin(digits),
        Iter alphabets_l = end(digits)) {
  hash_map<typename X::state, pair<T, T>, simple_hash<typename X::state>> prv, nxt;
  nxt[dfa.init()] = pair(T(0), T(1));
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) {
          nxt[s2].first += k.first * 10 + (*p-'0') * k.second;
          nxt[s2].second += k.second;
        }
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt) if (dfa.accept(s)) ans += k.first;
  return ans;
}

}  // namespace dfa
#line 3 "lib/dfa/multiple_of.hpp"

namespace dfa {

template <class T>
struct multiple_of : dfa_default {
  T d;
  constexpr multiple_of(T d) : d(d) {}

  using alphabet = char;
  using state = T;
  state init() const { return 0; }
  state next(state s, alphabet a, int) const {
    return (s * 10 + (a - '0')) % d;
  }
  bool accept(state s) const { return s == 0; }
};

}  // namespace dfa
#line 3 "lib/io.hpp"

struct int1 {
  int val; int1(int a = 1) : val(a - 1) {}
  operator int() const { return val; }
};

template <size_t BufSize = 1 << 26> class stdin_reader {
 public: stdin_reader() { buf[fread_unlocked(buf, 1, sizeof(buf), stdin)] = 0; } template <class T> enable_if_t<is_integral_v<T>> read(T& x) { skip(); [[maybe_unused]] bool neg = false; if constexpr (is_signed_v<T>) neg = *p == '-' ? (p++, true) : false; x = 0; while (*p > ' ') x = x * 10 + (*p++ & 0x0F); if constexpr (is_signed_v<T>) x = neg ? -x : x; } template <class T> void_t<decltype(&T::val)> read(T& x) { x = T((unsigned)(*this)); } void read(char*& q) { skip(); q = p; while (*p > ' ') p++; *p = 0; } template <size_t N> void read(char (&s)[N]) { read(s); } void read(string& s) { skip(); char* p0 = p; while (*p > ' ') p++; s.assign(p0, p); } template <class T, void_t<decltype(tuple_size<T>::value)>* = nullptr> void read(T& x) { read_tuple_impl(x, make_index_sequence<tuple_size_v<T>>{}); } template <class T, class U> void read(pair<T, U>& x) { read(x.first), read(x.second); } template <class T, size_t N> void read(T (&a)[N]) { for (auto& e : a) read(e); } template <class T> operator T() { T x; return read(x), x; } template <class... Ts> void operator()(Ts&... xs) { (read(xs), ...); } int operator--() { return (int)*this - 1; } template <class T> T* arr(int n) { T* p = new T[n + 1]; rep(i, n) read(p[i]); return p; } template <class T> void vec(vector<T>& v, int n) { v.resize(n); for (auto& e : v) read(e); } template <class T> vector<T> vec(int n) { vector<T> v; return vec(v, n), v; } template <class... Ts> tuple<vector<Ts>...> vecs(int n) { tuple<vector<Ts>...> res; vecs_impl(res, n, make_index_sequence<sizeof...(Ts)>{}); return res; } template <class T> void vvec(vector<vector<T>>& v, int n, int m) { v.resize(n); for (auto& e : v) vec(e, m); } template <class T> vector<vector<T>> vvec(int n, int m) { vector<vector<T>> v; return vvec(v, n, m), v; } template <class... Ts> auto cols(int n) { return transpose(vec<tuple<Ts...>>(n)); } private: char buf[BufSize], *p = buf; void skip() { while (*p <= ' ') p++; } template <class T, size_t... Is> void read_tuple_impl(T& x, index_sequence<Is...>) { (*this)(get<Is>(x)...); } template <class T, size_t... Is> void vecs_impl(T& x, int n, index_sequence<Is...>) { (vec(get<Is>(x), n), ...); } template <class T, size_t... Is> static auto transpose_impl(const vector<T>& v, index_sequence<Is...>) { tuple<vector<decay_t<tuple_element_t<Is, T>>>...> w; (get<Is>(w).reserve(v.size()), ...); for (const auto& row : v) (get<Is>(w).push_back(get<Is>(row)), ...); return w; } template <class T> static auto transpose(const vector<T>& v) { return transpose_impl(v, make_index_sequence<tuple_size_v<T>>{}); }
};
template <size_t BufSize = 1 << 26> class stdout_writer {
 public: ~stdout_writer() { flush(); } void flush() { fwrite_unlocked(buf, 1, p - buf, stdout), p = buf; } void write_char(char c) { *p++ = c; } void write() {} void write(char c) { write_char(c); } template <class T> enable_if_t<is_integral_v<T>> write(T x) { if (!x) return write_char('0'); if constexpr (is_signed_v<T>) if (x < 0) write_char('-'), x = -x; static char tmp[16]; char* q = end(tmp); while (x >= 10000) memcpy(q -= 4, digits.data + x % 10000 * 4, 4), x /= 10000; if (x < 10) write_char('0' + x); else if (x < 100) write_char('0' + (uint8_t)x / 10), write_char('0' + (uint8_t)x % 10); else if (x < 1000) memcpy(p, digits.data + x * 4 + 1, 3), p += 3; else memcpy(p, digits.data + x * 4, 4), p += 4; memcpy(p, q, end(tmp) - q), p += end(tmp) - q; } template <class T> void_t<decltype(&T::val)> write(T x) { write(x.val()); } void write(double x) { static char tmp[40]; sprintf(tmp, "%.15f", x); write(tmp); } void write(const char* s) { while (*s) *p++ = *s++; } void write(const string& s) { memcpy(p, s.c_str(), s.size()), p += s.size(); } template <class T, class U> void write(const pair<T, U>& x) { write(x.first), write_char(' '), write(x.second); } template <class... Ts> void write(const tuple<Ts...>& x) { write_tuple(x, make_index_sequence<sizeof...(Ts)>{}); } template <class... Ts> void write(const Ts&... xs) { ((write(xs), write_char(' ')), ...), --p; } template <class... Ts> void writeln(const Ts&... xs) { write(xs...), write_char('\n'); } template <class... Ts> void operator()(const Ts&... xs) { writeln(xs...); } template <class It> void iter(It first, It last, char sep = ' ') { if (first == last) write_char('\n'); else { while (first != last) write(*first++), write_char(sep); p[-1] = '\n'; } } void del() { *--p = 0; } void Yes(bool b = true) { writeln(b ? "Yes" : "No"); } void YES(bool b = true) { writeln(b ? "YES" : "NO"); } void Takahashi(bool b = true) { writeln(b ? "Takahashi" : "Aoki"); } private: char buf[BufSize], *p = buf; template <class T, size_t... Is> void write_tuple(const T& x, index_sequence<Is...>) { ((write(get<Is>(x)), write_char(' ')), ...), --p; } struct four_digits { char data[40000]; constexpr four_digits() : data() { for (int i = 0; i < 10000; i++) for (int n = i, j = 4; j--;) data[i * 4 + j] = n % 10 + '0', n /= 10; } } static constexpr digits{}; public:
#define INSTANT(s) void s() { writeln(#s); }
  INSTANT(No) INSTANT(NO) INSTANT(Aoki) INSTANT(possible) INSTANT(Possible) INSTANT(POSSIBLE) INSTANT(impossible) INSTANT(Impossible) INSTANT(IMPOSSIBLE)
#undef INSTANT
};
stdin_reader<> in;
stdout_writer<> out;
#line 5 "main.cpp"

enum zig_state {
  INC,
  DEC,
  ZERO,
  INIT,
  FAIL,
};

struct zig_zag : dfa::dfa_default {
  using state = pair<char, zig_state>;
  state init() const { return state('0', ZERO); }
  state next(state s, char c, int i) const {
    switch (s.second) {
      case FAIL:
        return s;
      case ZERO:
        if (c == '0')
          return s;
        else
          return state(c, INIT);
      case INIT:
        return state(c, s.first < c ? INC : s.first > c ? DEC : FAIL);
      case INC:
        return state(c, s.first > c ? DEC : FAIL);
      case DEC:
        return state(c, s.first < c ? INC : FAIL);
    }
    assert(false);
  }
  bool accept(state s) const { return s.second != FAIL; }
  bool unsuccessful(state s) const { return s.second == FAIL; }
};

int main() {
  string A = in, B = in;
  int n = B.size();
  A.insert(0, n - A.size(), '0');
  int M = in;
  auto dfa = dfa::land(zig_zag(),
                       dfa::land(dfa::multiple_of(M),
                                 dfa::land(dfa::leq(B.c_str()),
                                           dfa::lnot<dfa::lt>(A.c_str()))));
  mint ans = dfa::count<mint>(dfa, B.size());
  out(ans.val());
}
accuracy: 1
time_ms: 1120
memory_kb: 7716
final_rank: 17

code_snippet: #line 1 "lib/mod/modint.hpp"



#include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif

#line 1 "lib/atcoder/internal_math.hpp"



#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

// @param n `n < 2^32`
// @param m `1 <= m < 2^32`
// @return sum_{i=0}^{n-1} floor((ai + b) / m) (mod 2^64)
unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        // y_max < m * (n + 1)
        // floor(y_max / m) <= n
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#line 1 "lib/atcoder/internal_type_traits.hpp"



#line 7 "lib/atcoder/internal_type_traits.hpp"

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


#line 14 "lib/mod/modint.hpp"

namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static constexpr mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    constexpr static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    constexpr static_modint(T v) : _v() {
        _v = (unsigned int)(v % umod());
    }

    constexpr unsigned int val() const { return _v; }

    constexpr mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    constexpr mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    constexpr mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    constexpr mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    constexpr mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    constexpr mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    constexpr mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    constexpr mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    constexpr mint operator+() const { return *this; }
    constexpr mint operator-() const { return mint() - *this; }

    constexpr mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    constexpr mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    constexpr friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    constexpr friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    constexpr friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    constexpr friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    constexpr friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    constexpr friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder


#line 2 "main.cpp"
using mint = atcoder::static_modint<10000>;
#line 2 "lib/prelude.hpp"
#ifndef LOCAL
#pragma GCC optimize("O3")
// #pragma GCC target("avx2")
#endif
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep2(i, m, n) for (auto i = (m); i < (n); i++)
#define rep(i, n) rep2(i, 0, n)
#define repr2(i, m, n) for (auto i = (n); i-- > (m);)
#define repr(i, n) repr2(i, 0, n)
#define all(x) begin(x), end(x)
template <class T> auto ndvec(int n, T e) { return vector(n, e); }
template <class... Ts> auto ndvec(int n, Ts... e) { return vector(n, ndvec(e...)); }
#line 3 "lib/util/seed.hpp"

auto seed() {
#if defined(LOCAL) || defined(FIX_SEED)
  return 314169265258979;
#endif
  return chrono::steady_clock::now().time_since_epoch().count();
}
#line 3 "lib/util/rand.hpp"

uint32_t rand32() {
  static uint32_t x = seed();
  x ^= x << 13;
  x ^= x >> 17;
  x ^= x << 5;
  return x;
}

uint64_t rand64() {
  return uint64_t(rand32()) << 32 | rand32();
}
#line 3 "lib/util/hash.hpp"

template <class T, class = void>
struct simple_hash : hash<T> {};

template <class T>
struct simple_hash<T, void_t<decltype(tuple_size<T>::value)>> {
  size_t operator()(const T& x) const {
    return hash_impl(x, make_index_sequence<tuple_size_v<T>>{});
  }

 private:
  template <size_t... Is>
  static size_t hash_impl(const T& x, index_sequence<Is...>) {
    size_t res = 0;
    ((void)(res ^=
            (res << 16) ^ simple_hash<tuple_element_t<Is, T>>{}(get<Is>(x))),
     ...);
    return res;
  }
};

uint64_t splitmix64(uint64_t x) {
  // http://xorshift.di.unimi.it/splitmix64.c
  x += 0x9e3779b97f4a7c15;
  x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
  x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
  return x ^ (x >> 31);
}

template <class T, class = void>
struct anti_hack_hash;

template <class T>
struct anti_hack_hash<T, enable_if_t<is_convertible_v<T, uint64_t>>> {
  size_t operator()(T x) const {
    static const uint64_t ofs = seed();
    return splitmix64((uint64_t)x + ofs);
  }
};

template <class T>
struct anti_hack_hash<T, void_t<decltype(tuple_size<T>::value)>> {
  size_t operator()(const T& x) const {
    return hash_impl(x, make_index_sequence<tuple_size_v<T>>{});
  }

 private:
  static auto make_seed() {
    array<uint64_t, tuple_size_v<T>> res;
    res[0] = seed();
    rep(i, tuple_size_v<T> - 1) res[i + 1] = splitmix64(res[i]) + seed();
    return res;
  }
  template <size_t... Is>
  static size_t hash_impl(const T& x, index_sequence<Is...>) {
    static auto seed = make_seed();
    size_t res = 0;
    ((void)(res = splitmix64(res + get<Is>(x) + get<Is>(seed))), ...);
    return res;
  }
};
#line 4 "lib/ds/hash_map.hpp"
#include <ext/pb_ds/assoc_container.hpp>

template <class K, class V, class Hash = anti_hack_hash<K>>
using hash_map = __gnu_pbds::gp_hash_table<K, V, Hash>;
#line 4 "lib/dfa.hpp"

namespace dfa {

struct dfa_default {
  using alphabet = char;
  template <class T>
  bool successful(T &&) const {
    return false;
  }
  template <class T>
  bool unsuccessful(T &&) const {
    return false;
  }
};

struct leq_lt_base {
  const char *p;
  leq_lt_base(const char *p) : p(p) {}

  using alphabet = char;
  using state = signed char;
  state init() const { return 0; }
  state next(state s, alphabet a, int i) const {
    return s ? s : (a > p[i]) - (a < p[i]);
  }
  bool successful(state s) const { return s == -1; }
  bool unsuccessful(state s) const { return s == 1; }
};

struct leq : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s != 1; }
};

struct lt : leq_lt_base {
  using leq_lt_base::leq_lt_base;
  bool accept(state s) const { return s == -1; }
};

template <class X>
struct lnot : X {
  using X::X;
  bool accept(typename lnot::state s) const { return !X::accept(s); }
  bool successful(typename lnot::state s) const { return X::unsuccessful(s); }
  bool unsuccessful(typename lnot::state s) const { return X::successful(s); }
};

template <class X, class Y>
struct land {
  X x;
  Y y;
  land(X x, Y y) : x(x), y(y) {}

  static_assert(is_same_v<typename X::alphabet, typename Y::alphabet>);
  using alphabet = typename X::alphabet;
  using state = pair<typename X::state, typename Y::state>;
  state init() const { return make_pair(x.init(), y.init()); }
  state next(state s, alphabet a, int i) const {
    return make_pair(x.next(s.first, a, i), y.next(s.second, a, i));
  }
  bool accept(state s) const {
    return x.accept(s.first) && y.accept(s.second);
  }
  bool successful(state s) const {
    return x.successful(s.first) && y.successful(s.second);
  }
  bool unsuccessful(state s) const {
    return x.unsuccessful(s.first) || y.unsuccessful(s.second);
  }
};

const string digits = "0123456789";

template <class T, class X, class Iter = string::const_iterator>
T count(const X &dfa, int n, Iter alphabets_f = begin(digits),
        Iter alphabets_l = end(digits)) {
  // hash_map<typename X::state, T> prv, nxt;
  map<typename X::state, T> prv, nxt;
  nxt[dfa.init()] = T(1);
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) nxt[s2] += k;
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt) if (dfa.accept(s)) ans += k;
  return ans;
}

template <class T, class X, class Iter = string::const_iterator>
T sum(const X &dfa, int n, Iter alphabets_f = begin(digits),
        Iter alphabets_l = end(digits)) {
  hash_map<typename X::state, pair<T, T>, simple_hash<typename X::state>> prv, nxt;
  nxt[dfa.init()] = pair(T(0), T(1));
  rep(i, n) {
    prv = move(nxt);
    nxt.clear();
    for (auto [s, k] : prv) {
      rep2(p, alphabets_f, alphabets_l) {
        auto s2 = dfa.next(s, *p, i);
        if (!dfa.unsuccessful(s2)) {
          nxt[s2].first += k.first * 10 + (*p-'0') * k.second;
          nxt[s2].second += k.second;
        }
      }
    }
  }
  T ans(0);
  for (auto [s, k] : nxt) if (dfa.accept(s)) ans += k.first;
  return ans;
}

}  // namespace dfa
#line 3 "lib/dfa/multiple_of.hpp"

namespace dfa {

template <class T>
struct multiple_of : dfa_default {
  T d;
  constexpr multiple_of(T d) : d(d) {}

  using alphabet = char;
  using state = T;
  state init() const { return 0; }
  state next(state s, alphabet a, int) const {
    return (s * 10 + (a - '0')) % d;
  }
  bool accept(state s) const { return s == 0; }
};

}  // namespace dfa
#line 3 "lib/io.hpp"

struct int1 {
  int val; int1(int a = 1) : val(a - 1) {}
  operator int() const { return val; }
};

template <size_t BufSize = 1 << 26> class stdin_reader {
 public: stdin_reader() { buf[fread_unlocked(buf, 1, sizeof(buf), stdin)] = 0; } template <class T> enable_if_t<is_integral_v<T>> read(T& x) { skip(); [[maybe_unused]] bool neg = false; if constexpr (is_signed_v<T>) neg = *p == '-' ? (p++, true) : false; x = 0; while (*p > ' ') x = x * 10 + (*p++ & 0x0F); if constexpr (is_signed_v<T>) x = neg ? -x : x; } template <class T> void_t<decltype(&T::val)> read(T& x) { x = T((unsigned)(*this)); } void read(char*& q) { skip(); q = p; while (*p > ' ') p++; *p = 0; } template <size_t N> void read(char (&s)[N]) { read(s); } void read(string& s) { skip(); char* p0 = p; while (*p > ' ') p++; s.assign(p0, p); } template <class T, void_t<decltype(tuple_size<T>::value)>* = nullptr> void read(T& x) { read_tuple_impl(x, make_index_sequence<tuple_size_v<T>>{}); } template <class T, class U> void read(pair<T, U>& x) { read(x.first), read(x.second); } template <class T, size_t N> void read(T (&a)[N]) { for (auto& e : a) read(e); } template <class T> operator T() { T x; return read(x), x; } template <class... Ts> void operator()(Ts&... xs) { (read(xs), ...); } int operator--() { return (int)*this - 1; } template <class T> T* arr(int n) { T* p = new T[n + 1]; rep(i, n) read(p[i]); return p; } template <class T> void vec(vector<T>& v, int n) { v.resize(n); for (auto& e : v) read(e); } template <class T> vector<T> vec(int n) { vector<T> v; return vec(v, n), v; } template <class... Ts> tuple<vector<Ts>...> vecs(int n) { tuple<vector<Ts>...> res; vecs_impl(res, n, make_index_sequence<sizeof...(Ts)>{}); return res; } template <class T> void vvec(vector<vector<T>>& v, int n, int m) { v.resize(n); for (auto& e : v) vec(e, m); } template <class T> vector<vector<T>> vvec(int n, int m) { vector<vector<T>> v; return vvec(v, n, m), v; } template <class... Ts> auto cols(int n) { return transpose(vec<tuple<Ts...>>(n)); } private: char buf[BufSize], *p = buf; void skip() { while (*p <= ' ') p++; } template <class T, size_t... Is> void read_tuple_impl(T& x, index_sequence<Is...>) { (*this)(get<Is>(x)...); } template <class T, size_t... Is> void vecs_impl(T& x, int n, index_sequence<Is...>) { (vec(get<Is>(x), n), ...); } template <class T, size_t... Is> static auto transpose_impl(const vector<T>& v, index_sequence<Is...>) { tuple<vector<decay_t<tuple_element_t<Is, T>>>...> w; (get<Is>(w).reserve(v.size()), ...); for (const auto& row : v) (get<Is>(w).push_back(get<Is>(row)), ...); return w; } template <class T> static auto transpose(const vector<T>& v) { return transpose_impl(v, make_index_sequence<tuple_size_v<T>>{}); }
};
template <size_t BufSize = 1 << 26> class stdout_writer {
 public: ~stdout_writer() { flush(); } void flush() { fwrite_unlocked(buf, 1, p - buf, stdout), p = buf; } void write_char(char c) { *p++ = c; } void write() {} void write(char c) { write_char(c); } template <class T> enable_if_t<is_integral_v<T>> write(T x) { if (!x) return write_char('0'); if constexpr (is_signed_v<T>) if (x < 0) write_char('-'), x = -x; static char tmp[16]; char* q = end(tmp); while (x >= 10000) memcpy(q -= 4, digits.data + x % 10000 * 4, 4), x /= 10000; if (x < 10) write_char('0' + x); else if (x < 100) write_char('0' + (uint8_t)x / 10), write_char('0' + (uint8_t)x % 10); else if (x < 1000) memcpy(p, digits.data + x * 4 + 1, 3), p += 3; else memcpy(p, digits.data + x * 4, 4), p += 4; memcpy(p, q, end(tmp) - q), p += end(tmp) - q; } template <class T> void_t<decltype(&T::val)> write(T x) { write(x.val()); } void write(double x) { static char tmp[40]; sprintf(tmp, "%.15f", x); write(tmp); } void write(const char* s) { while (*s) *p++ = *s++; } void write(const string& s) { memcpy(p, s.c_str(), s.size()), p += s.size(); } template <class T, class U> void write(const pair<T, U>& x) { write(x.first), write_char(' '), write(x.second); } template <class... Ts> void write(const tuple<Ts...>& x) { write_tuple(x, make_index_sequence<sizeof...(Ts)>{}); } template <class... Ts> void write(const Ts&... xs) { ((write(xs), write_char(' ')), ...), --p; } template <class... Ts> void writeln(const Ts&... xs) { write(xs...), write_char('\n'); } template <class... Ts> void operator()(const Ts&... xs) { writeln(xs...); } template <class It> void iter(It first, It last, char sep = ' ') { if (first == last) write_char('\n'); else { while (first != last) write(*first++), write_char(sep); p[-1] = '\n'; } } void del() { *--p = 0; } void Yes(bool b = true) { writeln(b ? "Yes" : "No"); } void YES(bool b = true) { writeln(b ? "YES" : "NO"); } void Takahashi(bool b = true) { writeln(b ? "Takahashi" : "Aoki"); } private: char buf[BufSize], *p = buf; template <class T, size_t... Is> void write_tuple(const T& x, index_sequence<Is...>) { ((write(get<Is>(x)), write_char(' ')), ...), --p; } struct four_digits { char data[40000]; constexpr four_digits() : data() { for (int i = 0; i < 10000; i++) for (int n = i, j = 4; j--;) data[i * 4 + j] = n % 10 + '0', n /= 10; } } static constexpr digits{}; public:
#define INSTANT(s) void s() { writeln(#s); }
  INSTANT(No) INSTANT(NO) INSTANT(Aoki) INSTANT(possible) INSTANT(Possible) INSTANT(POSSIBLE) INSTANT(impossible) INSTANT(Impossible) INSTANT(IMPOSSIBLE)
#undef INSTANT
};
stdin_reader<> in;
stdout_writer<> out;
#line 5 "main.cpp"

enum zig_state {
  INC,
  DEC,
  ZERO,
  INIT,
  FAIL,
};

struct zig_zag : dfa::dfa_default {
  using state = pair<char, zig_state>;
  state init() const { return state('0', ZERO); }
  state next(state s, char c, int i) const {
    switch (s.second) {
      case FAIL:
        return s;
      case ZERO:
        if (c == '0')
          return s;
        else
          return state(c, INIT);
      case INIT:
        return state(c, s.first < c ? INC : s.first > c ? DEC : FAIL);
      case INC:
        return state(c, s.first > c ? DEC : FAIL);
      case DEC:
        return state(c, s.first < c ? INC : FAIL);
    }
    assert(false);
  }
  bool accept(state s) const { return s.second != FAIL; }
  bool unsuccessful(state s) const { return s.second == FAIL; }
};

int main() {
  string A = in, B = in;
  int n = B.size();
  A.insert(0, n - A.size(), '0');
  int M = in;
  auto dfa = dfa::land(zig_zag(),
                       dfa::land(dfa::multiple_of(M),
                                 dfa::land(dfa::leq(B.c_str()),
                                           dfa::lnot<dfa::lt>(A.c_str()))));
  mint ans = dfa::count<mint>(dfa, B.size());
  out(ans.val());
}
accuracy: 1
time_ms: 2010
memory_kb: 6644
final_rank: 19

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<long double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

const int mod = 10000;

void add(int &x, int y) {
    x += y;
    if (x >= mod) x -= mod;
}

int slv(string s, int m) {
    {
        reverse(s.begin(), s.end());
        while (s.size() and s.back() == '0') s.pop_back();
        reverse(s.begin(), s.end());
        if (s.size() == 0) return 0;
    }
    int n = s.size();
    // mod m, ラスト, s以下, ジグザグ
    vector<vector<vector<vector<int>>>> dp(m, vector<vector<vector<int>>> (10, vector<vector<int>> (2, vector<int>(3))));
    for (int i = 0; i < n; ++i) {
        vector<vector<vector<vector<int>>>> ndp(m, vector<vector<vector<int>>> (10, vector<vector<int>> (2, vector<int>(3))));
        if (i == 0) {
            for (int j = 1; j < s[0]-'0'; j++) {
                ndp[j%m][j][1][2] = 1;
            }
            ndp[(s[0]-'0')%m][s[0]-'0'][0][2] = 1;
        }
        else {
            for (int j = 1; j < 10; ++j) {
                ndp[j%m][j][1][2] = 1;
            }
            for (int j = 0; j < m; ++j) {
                for (int k = 0; k < 10; ++k) {
                    for (int l = 0; l < 2; ++l) {
                        for (int r = 0; r < 3; ++r) {
                            if (!dp[j][k][l][r]) continue;
                            for (int p = 0; p <= 9; ++p) {
                                if (l == 0 and p > s[i]-'0') break;
                                if (k == p) continue;
                                int nl = l;
                                if (l == 0 and p < (s[i]-'0')) nl = 1;
                                int nr;
                                if (r == 2) {
                                    if (k > p) nr = 0;
                                    else nr = 1;
                                }
                                else if (r == 0) {
                                    if (k < p) nr = 1;
                                    else continue;
                                }
                                else {
                                    if (k > p) nr = 0;
                                    else continue;
                                }
                                add(ndp[(j*10+p)%m][p][nl][nr], dp[j][k][l][r]);
                            }
                        }
                    }
                }
            }
        }
        swap(dp, ndp);
    }
    int res = 0;
    for (int j = 0; j < 10; ++j) {
        for (int k = 0; k < 2; ++k) {
            for (int l = 0; l < 3; ++l) {
                add(res, dp[0][j][k][l]);
            }
        }
    }
    return res;
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    string a,b; cin >> a >> b;
    int m; cin >> m;
    for (int i = a.size()-1; i >= 0; i--) {
        if (a[i] != '0') {
            a[i]--;
            for (int j = i+1; j < a.size(); j++) {
                a[j] = '9';
            }
            break;
        }
    }
    cout << (slv(b,m) - slv(a,m) + mod) % mod << endl;
}
accuracy: 1
time_ms: 640
memory_kb: 4876
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll; typedef unsigned long long ull;
const int inf = 1e9; const ll llnf = 4e18;

template< class Tp > void chkmax( Tp &x , Tp y ) { x = max( x , y ); }
template< class Tp > void chkmin( Tp &x , Tp y ) { x = min( x , y ); }

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder

namespace atcoder {

namespace internal {

// @param m `1 <= m`
// @return x mod m
constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

// Fast modular multiplication by barrett reduction
// Reference: https://en.wikipedia.org/wiki/Barrett_reduction
// NOTE: reconsider after Ice Lake
struct barrett {
    unsigned int _m;
    unsigned long long im;

    // @param m `1 <= m < 2^31`
    barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    // @return m
    unsigned int umod() const { return _m; }

    // @param a `0 <= a < m`
    // @param b `0 <= b < m`
    // @return `a * b % m`
    unsigned int mul(unsigned int a, unsigned int b) const {
        // [1] m = 1
        // a = b = im = 0, so okay

        // [2] m >= 2
        // im = ceil(2^64 / m)
        // -> im * m = 2^64 + r (0 <= r < m)
        // let z = a*b = c*m + d (0 <= c, d < m)
        // a*b * im = (c*m + d) * im = c*(im*m) + d*im = c*2^64 + c*r + d*im
        // c*r + d*im < m * m + m * im < m * m + 2^64 + m <= 2^64 + m * (m + 1) < 2^64 * 2
        // ((ab * im) >> 64) == c or c + 1
        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

// @param n `0 <= n`
// @param m `1 <= m`
// @return `(x ** n) % m`
constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

// Reference:
// M. Forisek and J. Jancina,
// Fast Primality Testing for Integers That Fit into a Machine Word
// @param n `0 <= n`
constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

// @param b `1 <= b`
// @return pair(g, x) s.t. g = gcd(a, b), xa = g (mod b), 0 <= x < b/g
constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    // Contracts:
    // [1] s - m0 * a = 0 (mod b)
    // [2] t - m1 * a = 0 (mod b)
    // [3] s * |m1| + t * |m0| <= b
    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b

        // [3]:
        // (s - t * u) * |m1| + t * |m0 - m1 * u|
        // <= s * |m1| - t * u * |m1| + t * (|m0| + |m1| * u)
        // = s * |m1| + t * |m0| <= b

        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    // by [3]: |m0| <= b/g
    // by g != b: |m0| < b/g
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

// Compile time primitive root
// @param m must be prime
// @return primitive root (and minimum in now)
constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

}  // namespace internal

}  // namespace atcoder

namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }
    static_modint(bool v) { _v = ((unsigned int)(v) % umod()); }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }
    dynamic_modint(bool v) { _v = ((unsigned int)(v) % mod()); }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt = 998244353;

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

using modint = atcoder::static_modint< 10000 >;

void solve( ) {
	// [ 0 , ... , s - l ] 中有多少个符合条件的数.
	auto calc = [&] ( string s , int k , int l ) -> modint {
		vector< vector< array< array< array< modint , 2 > , 3 > , 11 > > > dp( ( int ) s.size( ) , vector< array< array< array< modint , 2 > , 3 > , 11 > >( k ) );
		vector< vector< array< array< array< bool , 2 > , 3 > , 11 > > > vis( ( int ) s.size( ) , vector< array< array< array< bool , 2 > , 3 > , 11 > >( k ) );
		for( int i = 0; i < ( int ) s.size( ); i ++ ) for( int u = 0; u < k; u ++ ) for( int v = -1; v < 10; v ++ ) for( int w = -1; w <= 1; w ++ ) for( int p = 0; p <= 1; p ++ )
			dp[i][u][v + 1][w + 1][p] = 0 , vis[i][u][v + 1][w + 1][p] = false;

		auto dfs = [&] ( auto dfs , int i , int u , int v , int w , int p ) -> modint {
			if( i == -1 ) return ( p && l ) ? ( 0 ) : ( ( !u ) ? ( 1 ) : ( 0 ) );
			if( vis[i][u][v + 1][w + 1][p] ) return dp[i][u][v + 1][w + 1][p];

			modint ans = 0; int a = ( v == -1 ? 1 : 0 ) , b = ( p ? s[( int ) s.size( ) - i - 1] - '0' : 9 );
			for( int c = a; c <= b; c ++ ) if( c != v && ( w == -1 || w == ( c < v ) ) )
				ans += dfs( dfs , i - 1 , ( 10 * u + c ) % k , c , ( v == -1 ? -1 : c > v ) , p & ( c == b ) );
			if( v == -1 ) ans += dfs( dfs , i - 1 , 0 , -1 , -1 , false );
			return vis[i][u][v + 1][w + 1][p] = true , dp[i][u][v + 1][w + 1][p] = ans;
		} ;
		modint ans = dfs( dfs , ( int ) s.size( ) - 1 , 0 , -1 , -1 , true );
		return ans;
	} ;

	string L , R; int k; cin >> L >> R >> k;
	cout << ( calc( R , k , 0 ) - calc( L , k , 1 ) ).val( ) << "\n";
}

int main( ) {
	ios::sync_with_stdio( 0 ), cin.tie( 0 ), cout.tie( 0 );
	int T = 1; while( T -- ) solve( ); return 0;
}
accuracy: 1
time_ms: 480
memory_kb: 84200
final_rank: 16

code_snippet: #include<bits/stdc++.h>
#define ll long long
#define lll __int128
#define db double
#define ld long double
#define pii pair<int,int>
#define fi first
#define se second
#define vi vector<int>
using namespace std;
namespace IO
{
	const int SZ=1<<20;
	char gchar()
	{
	    static char buf[SZ];
	    static int i=SZ;
	    if(i==SZ)i=0,fread(buf,1,SZ,stdin);
	    return buf[i++];
	}
	void pchar(char c)
	{
	    static char buf[SZ];
	    static int i=0;
	    if(c)buf[i++]=c;
	    if(!c||i==SZ)fwrite(buf,1,i,stdout),i=0;
	}
	void pstr(string s,char end='\n')
	{
		for(char c:s)pchar(c);
		pchar(end);
	}
	template<typename T>void read(T &x)
	{
	    x=0;int f=1;
	    static char c;
	    while((c=gchar())>'9'||c<'0')if(c=='-')f=-1;
	    x=c-'0';
	    while((c=gchar())>='0'&&c<='9')
			x=(x<<1)+(x<<3)+(c^48);
		x*=f;
	}
	template<typename T,typename ...Args>void read(T &x,Args&...args){read(x),read(args...);}
	template<typename T>void i_write(T x)
	{
	    if(x>9)i_write(x/10);
	    pchar(x%10+'0');
	}
	template<typename T>void write(T x,char end='\n')
	{
	    if(x<0)pchar('-'),x=-x;
	    if(x>9)i_write(x/10);
	    pchar(x%10+'0');
	    pchar(end);
	}
}
using IO::read;
using IO::write;
const int N=510,mod=10000;
int m,f[N][N][10][2][2][2],s[N];
char a[N],b[N];
int dfs(int x,int r,int pr,int flg,int lim,int zer)
{
	if(!x)return !r&&!zer;
	if(f[x][r][pr][flg][lim][zer]!=-1)return f[x][r][pr][flg][lim][zer];
	f[x][r][pr][flg][lim][zer]=0;int mx=lim?s[x]:9;
	for(int i=0;i<=mx;i++)
	{
		if(!zer&&(i==pr||(i<pr)==flg))continue;
		f[x][r][pr][flg][lim][zer]=(f[x][r][pr][flg][lim][zer]+dfs(x-1,(r*10+i)%m,i,!flg,lim&&i==mx,zer&&!i))%mod;
	}
	return f[x][r][pr][flg][lim][zer];
}
int main()
{
	scanf("%s%s%d",a+1,b+1,&m);int na=strlen(a+1),nb=strlen(b+1);
	reverse(a+1,a+na+1),reverse(b+1,b+nb+1);
	for(int i=1;i<=na;i++)s[i]=a[i]-'0';
	s[1]--;
	for(int i=1;i<=na;i++)
		if(s[i]>=0)break;
		else s[i]+=10,s[i+1]--;
	while(na&&!s[na])na--;
	int ans=0;
	if(na)
	{
		memset(f,-1,sizeof(f));
		int res=(dfs(na,0,0,0,1,1)+dfs(na,0,0,1,1,1))%mod;
		for(int i=1;i<=(na>1?9:s[1]);i++)res-=(i%m==0);
		ans=(mod-res)%mod;
	}
	for(int i=1;i<=nb;i++)s[i]=b[i]-'0';
	if(nb)
	{
		memset(f,-1,sizeof(f));
		int res=(dfs(nb,0,0,0,1,1)+dfs(nb,0,0,1,1,1))%mod;
		for(int i=1;i<=(nb>1?9:s[1]);i++)res-=(i%m==0);
		ans=(ans+res)%mod;
	}
	printf("%d\n",ans);
	IO::pchar(0);
	return 0;
}
accuracy: 1
time_ms: 440
memory_kb: 85492
final_rank: 14

code_snippet: #include<bits/stdc++.h>
using namespace std;
const int mod=10000;
char L[510],R[510];
int p[510];
int m,n,ans;
int dp[510][510][10][4][2];
int dfs(int x,int y,int i,int j,int k){
	if(x==n+1)return !y&&(j>0);
	if(dp[x][y][i][j][k]!=-1)return dp[x][y][i][j][k];
	int ans=0;
	if(j){for(int z=0;z<=(k?9:p[x]);z++)if(i!=z&&(j==1||((i<z)^(j-2))))(ans+=dfs(x+1,(y*10+z)%m,z,(2+(i<z)),(k||(z<p[x]))))%=mod;}
	else{
		for(int z=0;z<=(k?9:p[x]);z++){
			if(!z)(ans+=dfs(x+1,0,0,0,(k||z<p[x])))%=mod;
			else (ans+=dfs(x+1,z%m,z,1,(k||z<p[x])))%=mod;
		}
	}
	return dp[x][y][i][j][k]=ans;
}
int main(){
	scanf("%s%s%d",L+1,R+1,&m);
	n=strlen(R+1);
	for(int i=1;i<=n;i++)p[i]=R[i]-'0';
	memset(dp,-1,sizeof(dp));
	int ans=dfs(1,0,0,0,0);
	n=strlen(L+1);
	for(int i=1;i<=n;i++)p[i]=L[i]-'0';
	memset(dp,-1,sizeof(dp));
	(ans-=dfs(1,0,0,0,0))%=mod;
	bool fl=1;
	for(int i=1;i+2<=n;i++)fl&=((p[i]<p[i+1])^(p[i+1]<p[i+2]));
	for(int i=1;i<n;i++)fl&=(p[i]!=p[i+1]);
	int X=0;
	for(int i=1;i<=n;i++)X=(X*10+p[i])%m;
	fl&=(!X);
	if(fl)(ans+=1)%=mod;
	return printf("%d\n",(ans+mod)%mod),0;
}
accuracy: 1
time_ms: 410
memory_kb: 84872
final_rank: 13

code_snippet: /**
 * 百夜の悲しき、常闇に。
 * カヒコの来世を、統神に祷む。
*/

#include <bits/stdc++.h>
using namespace std;

#define inl // __attribute__((always_inline)) inline
template <typename T> inl bool read (T &x) {
	x = 0; int f = 1; char c = getchar ();
	for (; c != EOF && !isdigit (c); c = getchar ())
		if (c == '-') f = -1;
	if (c == EOF) return 0;
	for (; c != EOF && isdigit (c); c = getchar ())
		x = (x<<1) + (x<<3) + (c^48);
	x *= f; return 1;
}
template <typename T, typename... Targs>
inl bool read (T &x, Targs&... args) {
	return read (x) && read (args...); }
template <typename T> void print (T x) {
	if (x < 0) putchar ('-'), x = -x;
	if (x > 9) print (x / 10);
	putchar ('0' + x % 10);
}
template <typename T, typename... Targs>
inl void print (T x, Targs... args) {
	print (x), putchar (' '), print (args...); }

#define newl putchar('\n')
typedef long long ll;
// typedef unsigned long long ull;
// typedef __int128 lll;
// typedef long double llf;
typedef pair <int, int> pint;
#define fst first
#define scd second
#define all(p) begin (p), end (p)
#define empb emplace_back

constexpr int N = 512, M = 512, P = 10000;
int m, n1, n2; char s[N], t[N];

inl bool zigzag (const char s[], int n) {
	for (int x = 1; x < n; ++x)
		if (s[x] == s[x+1]) return 0;
	for (int x = 2; x < n; ++x)
		if ((s[x]<s[x-1]) == (s[x+1]<s[x])) return 0;
	return 1;
}
template <bool incl_bd>
inl int calc (char s[], int n) {
	if (n == 1) return (s[1]-'0')/m - !incl_bd*((s[1]-'0') % m == 0);
	static int f[M][10][2], _f[M][10][2];
	const auto append = [&] (bool down, bool up, int pre, int lbd, int rbd) {
		for (int d = lbd; d <= rbd; ++d)
			_f[(d + pre) % m][d][0] += down,
			_f[(d + pre) % m][d][1] += up;
	};
	memset (f, 0, sizeof f); int pre = 0;
	for (int i = 0, ok = 1, c, par = 1; i < n; ++i) {
		memset (_f, 0, sizeof _f);
		c = s[i+1] - '0';
		append (i < n-1, 1, 0, 1, !i ? c - 1 : 9);
		if (!ok || !i);
		else append (par, 0, pre*10, 0, min (c, s[i]-'0')-1),
			append (0, i == 1 || !par, pre*10, s[i]-'0'+1, c-1);
		for (int x = 0; x < m; ++x)
			for (int d = 0; d < 10; ++d) {
				for (int _d = d + 1; _d < 10; ++_d)
					_f[(x*10+_d)%m][_d][1] += f[x][d][0];
				for (int _d = 0; _d < d; ++_d)
					_f[(x*10+_d)%m][_d][0] += f[x][d][1];
			}
		if (i) ok &= s[i] != s[i+1] && (i == 1
			|| (s[i+1]<s[i]) != (s[i]<s[i-1])),
			par = s[i+1] > s[i];
		pre = (pre * 10 + c) % m;
		for (int x = 0; x < m; ++x)
			for (int d = 0; d < 10; ++d)
				f[x][d][0] = _f[x][d][0] % P,
				f[x][d][1] = _f[x][d][1] % P;
	}
	return (zigzag (s, n) * !pre * incl_bd + accumulate (f[0], f[0] + 10,
		0ll, [] (int x, int *pt) { return x + pt[0] + pt[1]; })) % P;
}

int main () {
	/*  */
	#ifdef LOCAL
	freopen ("Aizu0570.in", "r", stdin);
	freopen ("Aizu0570.out", "w", stdout);
	#endif
	scanf ("%s%s%d", s + 1, t + 1, &m);
	n1 = strlen (s + 1),
	n2 = strlen (t + 1);
	print ((calc <1> (t, n2) + P-calc <0> (s, n1)) % P); newl;

	return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 3536
final_rank: 1

code_snippet: /**
 *   @FileName	a.cpp
 *   @Author	kanpurin
 *   @Created	2022.10.30 05:49:47
**/

#include "bits/stdc++.h" 
using namespace std; 
typedef long long ll;


template< int MOD >
struct mint {
public:
    unsigned int x;
    mint() : x(0) {}
    mint(long long v) {
        long long w = (long long)(v % (long long)(MOD));
        if (w < 0) w += MOD;
        x = (unsigned int)(w);
    }
    mint(std::string &s) {
        unsigned int z = 0;
        for (int i = 0; i < s.size(); i++) {
            z *= 10;
            z += s[i] - '0';
            z %= MOD;
        }
        x = z;
    }
    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }
    mint& operator+=(const mint &a) {
        if ((x += a.x) >= MOD) x -= MOD;
        return *this;
    }
    mint& operator-=(const mint &a) {
        if ((x -= a.x) >= MOD) x += MOD;
        return *this;
    }
    mint& operator*=(const mint &a) {
        unsigned long long z = x;
        z *= a.x;
        x = (unsigned int)(z % MOD);
        return *this;
    }
    mint& operator/=(const mint &a) {return *this = *this * a.inv(); }
    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs.x == rhs.x;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs.x != rhs.x;
    }
    friend std::ostream& operator<<(std::ostream &os, const mint &n) {
        return os << n.x;
    }
    friend std::istream &operator>>(std::istream &is, mint &n) {
        unsigned int x;
        is >> x;
        n = mint(x);
        return is;
    }
    mint inv() const {
        assert(x);
        return pow(MOD-2);
    }
    mint pow(long long n) const {        
        assert(0 <= n);
        mint p = *this, r = 1;
        while (n) {
            if (n & 1) r *= p;
            p *= p;
            n >>= 1;
        }
        return r;
    }
    
    mint sqrt() const {
        if (this->x < 2) return *this;
        if (this->pow((MOD-1)>>1).x != 1) return mint(0);
        mint b = 1, one = 1;
        while (b.pow((MOD-1) >> 1) == 1) b += one;
        long long m = MOD-1, e = 0;
        while (m % 2 == 0) m >>= 1, e += 1;
        mint x = this->pow((m - 1) >> 1);
        mint y = (*this) * x * x;
        x *= (*this);
        mint z = b.pow(m);
        while (y.x != 1) {
            int j = 0;
            mint t = y;
            while (t != one) j += 1, t *= t;
            z = z.pow(1LL << (e-j-1));
            x *= z; z *= z; y *= z; e = j;
        }
        return x;
    }
};

constexpr int MOD = 10000;

struct Monoid {
    mint<MOD> val;
    bool undef = true;
    Monoid() { *this = zero(); }
    Monoid(long long val, bool undef = true) : val(val),
                                               undef(undef) {}
    static Monoid zero() { return Monoid(0); }
    static Monoid e() { return Monoid(1,false); }
    Monoid& operator+=(const Monoid &a) {
        if (this->undef) *this = a;
        else if (!a.undef) this->val += a.val;
        return *this;
    }
    Monoid& operator*=(int c) {
        return *this;
    }
    friend Monoid operator+(const Monoid& a, const Monoid& b) {
        return Monoid(a) += b;
    }
    friend Monoid operator*(const Monoid& a, int c) {
        return Monoid(a) *= c;
    }
    friend std::ostream& operator<<(std::ostream &os, const Monoid &x) {
        return os << x.val;
    }
};

struct Automaton {
    vector<vector<int>> delta;
    vector<bool> is_accept, is_reject;
    int init;
    int alphabet_size = 10;
    int next(int state, int c) const { return delta[state][c]; }
    bool accept(int state) const { return is_accept[state]; }
    bool reject(int state) const { return is_reject[state]; }
    int size() const {return delta.size(); }
};
 
template<class Automaton1, class Automaton2>
Automaton intersectionAutomaton(const Automaton1 &A, const Automaton2 &B) {
    assert(A.alphabet_size == B.alphabet_size);
    Automaton M;
    M.alphabet_size = A.alphabet_size;
    vector<vector<int>> table(A.size(), vector<int>(B.size(),-1));
    vector<int> x = {A.init}, y = {B.init};
    table[x[0]][y[0]] = 0;
    M.init = 0;
    for (int i = 0; i < x.size(); ++i) {
        M.delta.push_back(vector<int>(10, -1));
        M.is_accept.push_back(A.accept(x[i]) && B.accept(y[i]));
        M.is_reject.push_back(A.reject(x[i]) || B.reject(y[i]));
        for (int c = 0; c < A.alphabet_size; c++) {
            int u = A.next(x[i],c), v = B.next(y[i],c);
            if (table[u][v] == -1) {
                table[u][v] = x.size();
                x.push_back(u);
                y.push_back(v);
            }
            M.delta[i][c] = table[u][v];
        }
    }
    return M;
}
 
struct ModuloAutomaton : Automaton {
private:
    int mod;
    void set_init() { init = 0; }
 
    void set_delta() {
        int qsize = mod;
        delta.resize(qsize,vector<int>(alphabet_size));
        for (int state = 0; state < qsize; state++) {
            for (int c = 0; c < alphabet_size; c++) {
                delta[state][c] = (state*10+c)%mod;
            }
        }
    }
 
    void set_is_accept() {
        int qsize = mod;
        is_accept.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_accept[state] = state == 0;
        }
    }
 
    void set_is_reject() {
        int qsize = mod;
        is_reject.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_reject[state] = false;
        }
    }
public:
    ModuloAutomaton(int mod, int alpha_size = 10) : mod(mod) {
        alphabet_size = alpha_size;
        set_init();
        set_delta();
        set_is_accept();
        set_is_reject();
    }
};
 
struct ZigZagAutomaton : Automaton {
private:
    void set_init() { init = alphabet_size*3; }
 
    void set_delta() {
        int qsize = 2+alphabet_size*3;
        delta.resize(qsize,vector<int>(alphabet_size));
        for (int state = 0; state < qsize; state++) {
            for (int c = 0; c < alphabet_size; c++) {
                if (state == alphabet_size*3) {
                    if (c == 0)
                        delta[state][c] = alphabet_size*3;
                    else
                        delta[state][c] = c;
                }
                else if (state < alphabet_size) {
                    if (c < state)
                        delta[state][c] = alphabet_size+c;
                    else if (c > state)
                        delta[state][c] = alphabet_size*2+c;
                    else
                        delta[state][c] = alphabet_size*3+1;
                }
                else if (state < alphabet_size*2) {
                    if (c > state-alphabet_size)
                        delta[state][c] = alphabet_size*2+c;
                    else
                        delta[state][c] = alphabet_size*3+1;
                }
                else if (state < alphabet_size*3) {
                    if (c < state-alphabet_size*2)
                        delta[state][c] = alphabet_size+c;
                    else
                        delta[state][c] = alphabet_size*3+1;
                }
                else {
                    delta[state][c] = alphabet_size*3+1;
                }
            }
        }
    }
 
    void set_is_accept() {
        int qsize = size();
        is_accept.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_accept[state] = 0 <= state && state < alphabet_size*3;
        }
    }
 
    void set_is_reject() {
        int qsize = size();
        is_reject.resize(qsize);
        is_reject[alphabet_size*3+1] = true;
    }
public:
    ZigZagAutomaton(int alpha_size = 10) {
        alphabet_size = alpha_size;
        set_init();
        set_delta();
        set_is_accept();
        set_is_reject();
    }
};
 
template<typename Automaton>
Monoid digitDP(const string &s, const Automaton &dfa, bool eq = 1) {
    vector<int> alpha(dfa.alphabet_size);
    iota(alpha.begin(), alpha.end(), 0);
    vector<vector<Monoid>> dp(2,vector<Monoid>(dfa.size(),Monoid::zero()));
    dp[1][dfa.init] = Monoid::e();
    for (int i = 0; i < s.size(); i++) {
        vector<vector<Monoid>> dp2(2,vector<Monoid>(dfa.size(),Monoid::zero()));
        for (int tight = 0; tight <= 1; tight++) {
            for (int state = 0; state < dfa.size(); state++) {
                if (dfa.reject(state) || dp[tight][state].undef) continue;
                int lim = (tight ? s[i] - '0' : dfa.alphabet_size - 1);
                for (int c = 0; c <= lim; c++) {
                    int tight_ = tight && c == lim;
                    int state_ = dfa.next(state,c);
                    if (dfa.reject(state_)) continue;
                    dp2[tight_][state_] += dp[tight][state]*c;
                }
            }
        }
        dp = dp2;
    }
    Monoid ans = Monoid::zero();
    for (int tight = 0; tight <= eq; tight++)
        for (int state = 0; state < dfa.size(); state++)
            if (dfa.accept(state)) ans += dp[tight][state];
    return ans;
}

mint<MOD> f(string &a,string &b,int m) {
    auto M1 = ZigZagAutomaton();
    auto M2 = ModuloAutomaton(m);
    auto M3 = intersectionAutomaton(M1,M2);
    return digitDP(b,M3).val-digitDP(a,M3,false).val;
}
 
int main() {
    string a,b;cin >> a >> b;
    int m;cin >> m;
    cout << f(a,b,m) << endl;
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 4152
final_rank: 2

code_snippet: /**
 *   @FileName	a.cpp
 *   @Author	kanpurin
 *   @Created	2022.10.28 10:52:42
**/

#include "bits/stdc++.h" 
using namespace std; 
typedef long long ll;


struct Monoid {
    ll val;
    Monoid identity() { return Monoid{0}; }
    friend Monoid operator+(const Monoid& l, const Monoid& r) {
        return Monoid{l.val + r.val};
    }
    friend Monoid operator*(const Monoid& l, const char c) {
        return l;
    }
};

struct Automaton {
    vector<vector<int>> delta;
    vector<bool> is_accept, is_reject;
    int init;
    int alphabet_size = 10;
    int next(int state, int c) const { return delta[state][c]; }
    bool accept(int state) const { return is_accept[state]; }
    bool reject(int state) const { return is_reject[state]; }
    int size() const {return delta.size(); }
};

template<class Automaton1, class Automaton2>
Automaton intersectionAutomaton(const Automaton1 &A, const Automaton2 &B) {
    assert(A.alphabet_size == B.alphabet_size);
    Automaton M;
    M.alphabet_size = A.alphabet_size;
    vector<vector<int>> table(A.size(), vector<int>(B.size(),-1));
    vector<int> x = {A.init}, y = {B.init};
    table[x[0]][y[0]] = 0;
    M.init = 0;
    for (int i = 0; i < x.size(); ++i) {
        M.delta.push_back(vector<int>(10, -1));
        M.is_accept.push_back(A.accept(x[i]) && B.accept(y[i]));
        M.is_reject.push_back(A.reject(x[i]) || B.reject(y[i]));
        for (int c = 0; c < A.alphabet_size; c++) {
            int u = A.next(x[i],c), v = B.next(y[i],c);
            if (table[u][v] == -1) {
                table[u][v] = x.size();
                x.push_back(u);
                y.push_back(v);
            }
            M.delta[i][c] = table[u][v];
        }
    }
    return M;
}

struct LeqAutomaton : public Automaton {
private:
    inline int _idx(int state) { return state/3; }
    inline int _comp(int state) { return state%3; }
    inline int tostate(int idx, int comp) { return idx*3+comp; }

    void set_init() { init = tostate(0,0); }

    void set_delta() {
        int qsize = (str.size()+1)*3;
        delta.resize(qsize,vector<int>(alphabet_size));
        for (int state = 0; state < qsize; state++) {
            int idx = _idx(state);
            int comp = _comp(state);
            if (idx < str.size()) {
                if (comp == 0) {
                    for (int c = 0; c < str[idx]-'0'; c++) 
                        delta[state][c] = tostate(idx+1,1);
                    for (int c = str[idx]-'0'+1; c < alphabet_size; c++)
                        delta[state][c] = tostate(idx+1,2);
                    delta[state][str[idx]-'0'] = tostate(idx+1,0);
                }
                else if (comp == 1) {
                    for (int c = 0; c < alphabet_size; c++)
                        delta[state][c] = tostate(idx+1,1);
                }
                else if (comp == 2) {
                    for (int c = 0; c < alphabet_size; c++)
                        delta[state][c] = tostate(idx+1,2);
                }
            }
            else {
                for (int c = 0; c < alphabet_size; c++)
                    delta[state][c] = tostate(str.size(),2);
            }
        }
    }

    void set_is_accept() {
        int qsize = (str.size()+1)*3;
        is_accept.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_accept[state] = _idx(state) == str.size() && _comp(state) != 2;
        }
    }

    void set_is_reject() {
        int qsize = (str.size()+1)*3;
        is_reject.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_reject[state] = _comp(state) == 2;
        }
    }
public:
    string str;

    LeqAutomaton(string s, int alpha_size = 10) {
        str = s;
        alphabet_size = alpha_size;
        set_init();
        set_delta();
        set_is_accept();
        set_is_reject();
    }
};

struct ModuloAutomaton : Automaton {
private:
    int mod;
    void set_init() { init = 0; }

    void set_delta() {
        int qsize = mod;
        delta.resize(qsize,vector<int>(alphabet_size));
        for (int state = 0; state < qsize; state++) {
            for (int c = 0; c < alphabet_size; c++) {
                delta[state][c] = (state*10+c)%mod;
            }
        }
    }

    void set_is_accept() {
        int qsize = mod;
        is_accept.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_accept[state] = state == 0;
        }
    }

    void set_is_reject() {
        int qsize = mod;
        is_reject.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_reject[state] = false;
        }
    }
public:
    ModuloAutomaton(int mod, int alpha_size = 10) : mod(mod) {
        alphabet_size = alpha_size;
        set_init();
        set_delta();
        set_is_accept();
        set_is_reject();
    }
};

struct SumOfDigitsAutomaton : Automaton {
private:
    int mod;
    void set_init() { init = 0; }

    void set_delta() {
        int qsize = mod;
        delta.resize(qsize,vector<int>(alphabet_size));
        for (int state = 0; state < qsize; state++) {
            for (int c = 0; c < alphabet_size; c++) {
                delta[state][c] = (state+c)%mod;
            }
        }
    }

    void set_is_accept() {
        int qsize = mod;
        is_accept.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_accept[state] = state == 0;
        }
    }

    void set_is_reject() {
        int qsize = mod;
        is_reject.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_reject[state] = false;
        }
    }
public:
    SumOfDigitsAutomaton(int mod, int alpha_size = 10) : mod(mod) {
        alphabet_size = alpha_size;
        set_init();
        set_delta();
        set_is_accept();
        set_is_reject();
    }
};

struct ZigZagAutomaton : Automaton {
private:
    void set_init() { init = alphabet_size*3; }

    void set_delta() {
        int qsize = 2+alphabet_size*3;
        delta.resize(qsize,vector<int>(alphabet_size));
        for (int state = 0; state < qsize; state++) {
            for (int c = 0; c < alphabet_size; c++) {
                if (state == alphabet_size*3) {
                    if (c == 0)
                        delta[state][c] = alphabet_size*3;
                    else
                        delta[state][c] = c;
                }
                else if (state < alphabet_size) {
                    if (c < state)
                        delta[state][c] = alphabet_size+c;
                    else if (c > state)
                        delta[state][c] = alphabet_size*2+c;
                    else
                        delta[state][c] = alphabet_size*3+1;
                }
                else if (state < alphabet_size*2) {
                    if (c > state-alphabet_size)
                        delta[state][c] = alphabet_size*2+c;
                    else
                        delta[state][c] = alphabet_size*3+1;
                }
                else if (state < alphabet_size*3) {
                    if (c < state-alphabet_size*2)
                        delta[state][c] = alphabet_size+c;
                    else
                        delta[state][c] = alphabet_size*3+1;
                }
                else {
                    delta[state][c] = alphabet_size*3+1;
                }
            }
        }
    }

    void set_is_accept() {
        int qsize = size();
        is_accept.resize(qsize);
        for (int state = 0; state < qsize; state++) {
            is_accept[state] = 0 <= state && state < alphabet_size*3;
        }
    }

    void set_is_reject() {
        int qsize = size();
        is_reject.resize(qsize);
        is_reject[alphabet_size*3+1] = true;
    }
public:
    ZigZagAutomaton(int alpha_size = 10) {
        alphabet_size = alpha_size;
        set_init();
        set_delta();
        set_is_accept();
        set_is_reject();
    }
};

template<typename Value, typename Automaton>
Value digitDP(int n, Value e, const Automaton &dfa) {
    struct T { Value val; };
    auto oplus = [&](const T &x, const T &y) -> T {
        return {x.val + y.val};
    };
    auto otimes = [&](const T &x, int c) {
        return x;
    };
    vector<int> alpha(dfa.alphabet_size);
    iota(alpha.begin(), alpha.end(), 0);
    unordered_map<int,T> dp,dp2;
    dp[dfa.init] = {e};
    for (int i = 0; i < n; i++) {
        for (auto [state,val] : dp) {
            for (int c : alpha) {
                auto n_state = dfa.next(state,c);
                if (dfa.reject(n_state)) continue;
                dp2[n_state] = oplus(dp2[n_state],otimes(dp[state],c));
            }
        }
        dp.swap(dp2); dp2.clear();
    }
    T ans;
    for (auto [state,val] : dp) {
        if (dfa.accept(state)) ans = oplus(ans,val);
    }
    return ans.val;
}

template<typename Value, typename Automaton>
Value digitDP(string s, Value e, const Automaton &dfa, bool eq = 1) {
    struct T { Value val; };
    auto oplus = [&](const T &x,const  T &y) -> T {
        return {x.val + y.val};
    };
    auto otimes = [&](const T &x, int c) {
        return x;
    };
    vector<int> alpha(dfa.alphabet_size);
    iota(alpha.begin(), alpha.end(), 0);
    vector<vector<T>> dp(2,vector<T>(dfa.size()));
    dp[1][dfa.init] = {e};
    for (int i = 0; i < s.size(); i++) {
        vector<vector<T>> dp2(2,vector<T>(dfa.size()));
        for (int tight = 0; tight <= 1; tight++) {
            for (int state = 0; state < dfa.size(); state++) {
                if (dfa.reject(state)) continue;
                int lim = (tight ? s[i] - '0' : 9);
                for (int c = 0; c <= lim; c++) {
                    int tight_ = tight && c == lim;
                    int state_ = dfa.next(state,c);
                    if (dfa.reject(state_)) continue;
                    dp2[tight_][state_] = oplus(dp2[tight_][state_],otimes(dp[tight][state],c));
                }
            }
        }
        dp = dp2;
    }
    T ans;
    for (int tight = 0; tight <= eq; tight++) {
        for (int state = 0; state < dfa.size(); state++) {
            if (dfa.accept(state)) ans = oplus(ans,dp[tight][state]);
        }
    }
    return ans.val;
}

template< int MOD >
struct mint {
public:
    unsigned int x;
    mint() : x(0) {}
    mint(long long v) {
        long long w = (long long)(v % (long long)(MOD));
        if (w < 0) w += MOD;
        x = (unsigned int)(w);
    }
    mint(std::string &s) {
        unsigned int z = 0;
        for (int i = 0; i < s.size(); i++) {
            z *= 10;
            z += s[i] - '0';
            z %= MOD;
        }
        x = z;
    }
    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }
    mint& operator+=(const mint &a) {
        if ((x += a.x) >= MOD) x -= MOD;
        return *this;
    }
    mint& operator-=(const mint &a) {
        if ((x -= a.x) >= MOD) x += MOD;
        return *this;
    }
    mint& operator*=(const mint &a) {
        unsigned long long z = x;
        z *= a.x;
        x = (unsigned int)(z % MOD);
        return *this;
    }
    mint& operator/=(const mint &a) {return *this = *this * a.inv(); }
    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs.x == rhs.x;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs.x != rhs.x;
    }
    friend std::ostream& operator<<(std::ostream &os, const mint &n) {
        return os << n.x;
    }
    friend std::istream &operator>>(std::istream &is, mint &n) {
        unsigned int x;
        is >> x;
        n = mint(x);
        return is;
    }
    mint inv() const {
        assert(x);
        return pow(MOD-2);
    }
    mint pow(long long n) const {        
        assert(0 <= n);
        mint p = *this, r = 1;
        while (n) {
            if (n & 1) r *= p;
            p *= p;
            n >>= 1;
        }
        return r;
    }
    
    mint sqrt() const {
        if (this->x < 2) return *this;
        if (this->pow((MOD-1)>>1).x != 1) return mint(0);
        mint b = 1, one = 1;
        while (b.pow((MOD-1) >> 1) == 1) b += one;
        long long m = MOD-1, e = 0;
        while (m % 2 == 0) m >>= 1, e += 1;
        mint x = this->pow((m - 1) >> 1);
        mint y = (*this) * x * x;
        x *= (*this);
        mint z = b.pow(m);
        while (y.x != 1) {
            int j = 0;
            mint t = y;
            while (t != one) j += 1, t *= t;
            z = z.pow(1LL << (e-j-1));
            x *= z; z *= z; y *= z; e = j;
        }
        return x;
    }
};

constexpr int MOD = 10000;

int main() {
    string a,b;cin >> a >> b;
    int d;cin >> d;
    ZigZagAutomaton zigzag;
    ModuloAutomaton modulo(d);
    Automaton dfa = intersectionAutomaton(zigzag,modulo);
    cout << digitDP(b,mint<MOD>(1),dfa)-digitDP(a,mint<MOD>(1),dfa,false) << endl;
    return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 4008
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#include <cassert>
typedef long long int ll;
using namespace std;
// #include <atcoder/all>
// using namespace atcoder;
#define REP2(i, a, b) for (ll i = (a); i < (b); i++)
#define REP2R(i, a, b) for (ll i = (a); i >= (b); i--)
#define REP(i, b) REP2(i, 0, b)
#define ALL(coll) (coll).begin(), (coll).end()
#define SIZE(v) ((ll)((v).size()))

// @@ !! LIM(mod debug cmpNaive)

// ---- inserted function f:gcd from util.cc

tuple<ll, ll, ll> mut_div(ll a, ll b, ll c, bool eff_c = true) {
  // auto [g, s, t] = mut_div(a, b, c, eff_c)
  //    If eff_c is true (default),
  //        g == gcd(|a|, |b|) and as + bt == c, if such s,t exists
  //        (g, s, t) == (-1, -1, -1)            otherwise
  //    If eff_c is false,                                 
  //        g == gcd(|a|, |b|) and as + bt == g           
  //    N.b.  gcd(0, t) == gcd(t, 0) == t.
  if (a == 0) {
    if (eff_c) {
      if (c % b != 0) return {-1, -1, -1};
      else            return {abs(b), 0, c / b};
    }else {
      if (b < 0) return {-b, 0, -1};
      else       return { b, 0,  1};
    }
  }else {
    auto [g, t, u] = mut_div(b % a, a, c, eff_c);
    // DLOGK(b%a, a, c, g, t, u);
    if (g == -1) return {-1, -1, -1};
    return {g, u - (b / a) * t, t};
  }
}

// auto [g, s, t] = eGCD(a, b)  --->  sa + tb == g == gcd(|a|, |b|)
//    N.b.  gcd(0, t) == gcd(t, 0) == t.
tuple<ll, ll, ll> eGCD(ll a, ll b) { return mut_div(a, b, 0, false); }

pair<ll, ll> crt_sub(ll a1, ll x1, ll a2, ll x2) {
  // DLOGKL("crt_sub", a1, x1, a2, x2);
  a1 = a1 % x1;
  a2 = a2 % x2;
  auto [g, s, t] = mut_div(x1, -x2, a2 - a1);
  // DLOGK(g, s, t);
  if (g == -1) return {-1, -1};
  ll z = x1 / g * x2;
  // DLOGK(z);
  s = s % (x2 / g);
  ll r = (x1 * s + a1) % z;
  // DLOGK(r);
  if (r < 0) r += z;
  // DLOGK(r);
  return {r, z};
};

// Chinese Remainder Theorem
//
//    r = crt(a1, x1, a2, x2)
//    ==>   r = a1 (mod x1);  r = a2 (mod x2);  0 <= r < lcm(x1, x2)
//    If no such r exists, returns -1
//    Note: x1 and x2 should >= 1.  a1 and a2 can be negative or zero.
//
//    r = crt(as, xs)
//    ==>   for all i. r = as[i] (mod xs[i]); 0 <= r < lcm(xs)
//    If no such r exists, returns -1
//    Note: xs[i] should >= 1.  as[i] can be negative or zero.
//          It should hold: len(xs) == len(as) > 0

ll crt(ll a1, ll x1, ll a2, ll x2) { return crt_sub(a1, x1, a2, x2).first; }

ll crt(vector<ll> as, vector<ll> xs) {
  // DLOGKL("crt", as, xs);
  assert(xs.size() == as.size() && xs.size() > 0);
  ll r = as[0];
  ll z = xs[0];
  for (size_t i = 1; i < xs.size(); i++) {
    // DLOGK(i, r, z, as[i], xs[i]);
    tie(r, z) = crt_sub(r, z, as[i], xs[i]);
    // DLOGK(r, z);
    if (r == -1) return -1;
  }
  return r;
}

// ---- end f:gcd

// ---- inserted library file mod.cc

template<int mod=0>
struct FpG {   // G for General
  static ll dyn_mod;

  static ll getMod() {
    if (mod == 0) return dyn_mod;
    else          return mod;
  }

  static void setMod(ll _mod) {  // effective only when mod == 0
    dyn_mod = _mod;
  }

  static ll _conv(ll x) {
    if (x >= getMod())  return x % getMod();
    if (x >= 0)         return x;
    if (x >= -getMod()) return x + getMod();
    ll y = x % getMod();
    if (y == 0) return 0;
    return y + getMod();
  }

  ll val;

  FpG(int t = 0) : val(_conv(t)) {}
  FpG(ll t) : val(_conv(t)) {}
  FpG(const FpG& t) : val(t.val) {}
  FpG& operator =(const FpG& t) { val = t.val; return *this; }
  FpG& operator =(ll t) { val = _conv(t); return *this; }
  FpG& operator =(int t) { val = _conv(t); return *this; }

  FpG& operator +=(const FpG& t) {
    val += t.val;
    if (val >= getMod()) val -= getMod();
    return *this;
  }

  FpG& operator -=(const FpG& t) {
    val -= t.val;
    if (val < 0) val += getMod();
    return *this;
  }

  FpG& operator *=(const FpG& t) {
    val = (val * t.val) % getMod();
    return *this;
  }

  FpG inv() const {
    if (val == 0) {
      throw runtime_error("FpG::inv(): called for zero.");
    }
    auto [g, u, v] = eGCD(val, getMod());
    return FpG(u);
  }

  FpG& operator /=(const FpG& t) {
    return (*this) *= t.inv();
  }

  FpG operator +(const FpG& t) const { return FpG(val) += t; }
  FpG operator -(const FpG& t) const { return FpG(val) -= t; }
  FpG operator *(const FpG& t) const { return FpG(val) *= t; }
  FpG operator /(const FpG& t) const { return FpG(val) /= t; }
  FpG operator -() const { return FpG(-val); }

  bool operator ==(const FpG& t) const { return val == t.val; }
  bool operator !=(const FpG& t) const { return val != t.val; }
  
  operator ll() const { return val; }

  friend FpG operator +(int x, const FpG& y) { return FpG(x) + y; }
  friend FpG operator -(int x, const FpG& y) { return FpG(x) - y; }
  friend FpG operator *(int x, const FpG& y) { return FpG(x) * y; }
  friend FpG operator /(int x, const FpG& y) { return FpG(x) / y; }
  friend bool operator ==(int x, const FpG& y) { return FpG(x) == y; }
  friend bool operator !=(int x, const FpG& y) { return FpG(x) != y; }
  friend FpG operator +(ll x, const FpG& y) { return FpG(x) + y; }
  friend FpG operator -(ll x, const FpG& y) { return FpG(x) - y; }
  friend FpG operator *(ll x, const FpG& y) { return FpG(x) * y; }
  friend FpG operator /(ll x, const FpG& y) { return FpG(x) / y; }
  friend bool operator ==(ll x, const FpG& y) { return FpG(x) == y; }
  friend bool operator !=(ll x, const FpG& y) { return FpG(x) != y; }
  friend FpG operator +(const FpG& x, int y) { return x + FpG(y); }
  friend FpG operator -(const FpG& x, int y) { return x - FpG(y); }
  friend FpG operator *(const FpG& x, int y) { return x * FpG(y); }
  friend FpG operator /(const FpG& x, int y) { return x / FpG(y); }
  friend bool operator ==(const FpG& x, int y) { return x == FpG(y); }
  friend bool operator !=(const FpG& x, int y) { return x != FpG(y); }
  friend FpG operator +(const FpG& x, ll y) { return x + FpG(y); }
  friend FpG operator -(const FpG& x, ll y) { return x - FpG(y); }
  friend FpG operator *(const FpG& x, ll y) { return x * FpG(y); }
  friend FpG operator /(const FpG& x, ll y) { return x / FpG(y); }
  friend bool operator ==(const FpG& x, ll y) { return x == FpG(y); }
  friend bool operator !=(const FpG& x, ll y) { return x != FpG(y); }

  friend istream& operator>> (istream& is, FpG& t) {
    ll x; is >> x;
    t = x;
    return is;
  }

  friend ostream& operator<< (ostream& os, const FpG& t) {
    os << t.val;
    return os;
  }

};
template<int mod>
ll FpG<mod>::dyn_mod;

template<int mod=0>
class CombG {
  int nMax;
  vector<FpG<mod>> vFact;
  vector<FpG<mod>> vInvFact;
public:
  CombG(int nm) : nMax(nm), vFact(nm+1), vInvFact(nm+1) {
    vFact.at(0) = 1;
    for (int i = 1; i <= nMax; i++) vFact.at(i) = i * vFact.at(i-1);
    vInvFact.at(nMax) = vFact.at(nMax).inv();
    for (int i = nMax; i >= 1; i--) vInvFact.at(i-1) = i * vInvFact.at(i);
  }
  FpG<mod> fact(int n) { return vFact.at(n); }
  FpG<mod> comb(int n, int r) {
    if (r < 0 || r > n) return 0;
    return vFact.at(n) * vInvFact.at(r) * vInvFact.at(n-r);
  }
  // The number of permutation extracting r from n.
  FpG<mod> perm(int n, int r) {
    return vFact.at(n) * vInvFact.at(n-r);
  }
};

constexpr int primeA = 1'000'000'007;
constexpr int primeB = 998'244'353;          // '
using FpA = FpG<primeA>;
using FpB = FpG<primeB>;
using CombA = CombG<primeA>;
using CombB = CombG<primeB>;

// ---- end mod.cc

// ---- inserted function f:<< from util.cc
template <typename T1, typename T2>
ostream& operator<< (ostream& os, const pair<T1,T2>& p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}

template <typename T1, typename T2, typename T3>
ostream& operator<< (ostream& os, const tuple<T1,T2,T3>& t) {
  os << "(" << get<0>(t) << ", " << get<1>(t)
     << ", " << get<2>(t) << ")";
  return os;
}

template <typename T1, typename T2, typename T3, typename T4>
ostream& operator<< (ostream& os, const tuple<T1,T2,T3,T4>& t) {
  os << "(" << get<0>(t) << ", " << get<1>(t)
     << ", " << get<2>(t) << ", " << get<3>(t) << ")";
  return os;
}

template <typename T>
ostream& operator<< (ostream& os, const vector<T>& v) {
  os << '[';
  for (auto it = v.begin(); it != v.end(); it++) {
    if (it != v.begin()) os << ", ";
    os << *it;
  }
  os << ']';

  return os;
}

template <typename T, typename C>
ostream& operator<< (ostream& os, const set<T, C>& v) {
  os << '{';
  for (auto it = v.begin(); it != v.end(); it++) {
    if (it != v.begin()) os << ", ";
    os << *it;
  }
  os << '}';

  return os;
}

template <typename T, typename C>
ostream& operator<< (ostream& os, const unordered_set<T, C>& v) {
  os << '{';
  for (auto it = v.begin(); it != v.end(); it++) {
    if (it != v.begin()) os << ", ";
    os << *it;
  }
  os << '}';

  return os;
}

template <typename T, typename C>
ostream& operator<< (ostream& os, const multiset<T, C>& v) {
  os << '{';
  for (auto it = v.begin(); it != v.end(); it++) {
    if (it != v.begin()) os << ", ";
    os << *it;
  }
  os << '}';

  return os;
}

template <typename T1, typename T2, typename C>
ostream& operator<< (ostream& os, const map<T1, T2, C>& mp) {
  os << '[';
  for (auto it = mp.begin(); it != mp.end(); it++) {
    if (it != mp.begin()) os << ", ";
    os << it->first << ": " << it->second;
  }
  os << ']';

  return os;
}

template <typename T1, typename T2, typename C>
ostream& operator<< (ostream& os, const unordered_map<T1, T2, C>& mp) {
  os << '[';
  for (auto it = mp.begin(); it != mp.end(); it++) {
    if (it != mp.begin()) os << ", ";
    os << it->first << ": " << it->second;
  }
  os << ']';

  return os;
}

template <typename T, typename T2>
ostream& operator<< (ostream& os, const queue<T, T2>& orig) {
  queue<T, T2> que(orig);
  bool first = true;
  os << '[';
  while (!que.empty()) {
    T x = que.front(); que.pop();
    if (!first) os << ", ";
    os << x;
    first = false;
  }
  return os << ']';
}

template <typename T, typename T2>
ostream& operator<< (ostream& os, const deque<T, T2>& orig) {
  deque<T, T2> que(orig);
  bool first = true;
  os << '[';
  while (!que.empty()) {
    T x = que.front(); que.pop_front();
    if (!first) os << ", ";
    os << x;
    first = false;
  }
  return os << ']';
}

template <typename T, typename T2, typename T3>
ostream& operator<< (ostream& os, const priority_queue<T, T2, T3>& orig) {
  priority_queue<T, T2, T3> pq(orig);
  bool first = true;
  os << '[';
  while (!pq.empty()) {
    T x = pq.top(); pq.pop();
    if (!first) os << ", ";
    os << x;
    first = false;
  }
  return os << ']';
}

template <typename T>
ostream& operator<< (ostream& os, const stack<T>& st) {
  stack<T> tmp(st);
  os << '[';
  bool first = true;
  while (!tmp.empty()) {
    T& t = tmp.top();
    if (first) first = false;
    else os << ", ";
    os << t;
    tmp.pop();
  }
  os << ']';
  return os;
}

#if __cplusplus >= 201703L
template <typename T>
ostream& operator<< (ostream& os, const optional<T>& t) {
  if (t.has_value()) os << "v(" << t.value() << ")";
  else               os << "nullopt";
  return os;
}
#endif

ostream& operator<< (ostream& os, int8_t x) {
  os << (int32_t)x;
  return os;
}

// ---- end f:<<

// ---- inserted library file debug.cc
template <class... Args>
string dbgFormat(const char* fmt, Args... args) {
  size_t len = snprintf(nullptr, 0, fmt, args...);
  char buf[len + 1];
  snprintf(buf, len + 1, fmt, args...);
  return string(buf);
}

template <class Head>
void dbgLog(bool with_nl, Head&& head) {
  cerr << head;
  if (with_nl) cerr << endl;
}

template <class Head, class... Tail>
void dbgLog(bool with_nl, Head&& head, Tail&&... tail)
{
  cerr << head << " ";
  dbgLog(with_nl, forward<Tail>(tail)...);
}

#if DEBUG
  #define DLOG(...)        dbgLog(true, __VA_ARGS__)
  #define DLOGNNL(...)     dbgLog(false, __VA_ARGS__)
  #define DFMT(...)        cerr << dbgFormat(__VA_ARGS__) << endl
  #define DCALL(func, ...) func(__VA_ARGS__)
#else
  #define DLOG(...)
  #define DLOGNNL(...)
  #define DFMT(...)
  #define DCALL(func, ...)
#endif

/*
#if DEBUG_LIB
  #define DLOG_LIB(...)        dbgLog(true, __VA_ARGS__)
  #define DLOGNNL_LIB(...)     dbgLog(false, __VA_ARGS__)
  #define DFMT_LIB(...)        cerr << dbgFormat(__VA_ARGS__) << endl
  #define DCALL_LIB(func, ...) func(__VA_ARGS__)
#else
  #define DLOG_LIB(...)
  #define DFMT_LIB(...)
  #define DCALL_LIB(func, ...)
#endif
*/

#define DUP1(E1)       #E1 "=", E1
#define DUP2(E1,E2)    DUP1(E1), DUP1(E2)
#define DUP3(E1,...)   DUP1(E1), DUP2(__VA_ARGS__)
#define DUP4(E1,...)   DUP1(E1), DUP3(__VA_ARGS__)
#define DUP5(E1,...)   DUP1(E1), DUP4(__VA_ARGS__)
#define DUP6(E1,...)   DUP1(E1), DUP5(__VA_ARGS__)
#define DUP7(E1,...)   DUP1(E1), DUP6(__VA_ARGS__)
#define DUP8(E1,...)   DUP1(E1), DUP7(__VA_ARGS__)
#define DUP9(E1,...)   DUP1(E1), DUP8(__VA_ARGS__)
#define DUP10(E1,...)   DUP1(E1), DUP9(__VA_ARGS__)
#define DUP11(E1,...)   DUP1(E1), DUP10(__VA_ARGS__)
#define DUP12(E1,...)   DUP1(E1), DUP11(__VA_ARGS__)
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,NAME,...) NAME
#define DUP(...)          GET_MACRO(__VA_ARGS__, DUP12, DUP11, DUP10, DUP9, DUP8, DUP7, DUP6, DUP5, DUP4, DUP3, DUP2, DUP1)(__VA_ARGS__)
#define DLOGK(...)        DLOG(DUP(__VA_ARGS__))
#define DLOGKL(lab, ...)  DLOG(lab, DUP(__VA_ARGS__))

#if DEBUG_LIB
  #define DLOG_LIB   DLOG
  #define DLOGK_LIB  DLOGK
  #define DLOGKL_LIB DLOGKL
#endif

// ---- end debug.cc

// ---- inserted library file cmpNaive.cc

const string end_mark("^__=end=__^");

int naive(istream& cin, ostream& cout);
int body(istream& cin, ostream& cout);

void cmpNaive() {
  while (true) {
    string s;
    getline(cin, s);
    bool run_body;
    if (s.at(0) == 'Q') {
      return;
    }else if (s.at(0) == 'B') {
      run_body = true;
    }else if (s.at(0) == 'N') {
      run_body = false;
    }else {
      cerr << "Unknown body/naive specifier.\n";
      exit(1);
    }
    string input_s;
    while (true) {
      getline(cin, s);
      if (s == end_mark) break;
      input_s += s;
      input_s += "\n";
    }
    stringstream ss_in(move(input_s));
    stringstream ss_out;
    if (run_body) {
      body(ss_in, ss_out);
    }else {
      naive(ss_in, ss_out);
    }
    cout << ss_out.str() << end_mark << endl;
  }
}

int main(int argc, char *argv[]) {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout << setprecision(20);

#if CMPNAIVE
  if (argc == 2) {
    if (strcmp(argv[1], "cmpNaive") == 0) {
      cmpNaive();
    }else if (strcmp(argv[1], "naive") == 0) {
      naive(cin, cout);
    }else if (strcmp(argv[1], "skip") == 0) {
      exit(0);
    }else {
      cerr << "Unknown argument.\n";
      exit(1);
    }
  }else {
#endif
    body(cin, cout);
#if CMPNAIVE
  }
#endif
  return 0;
}

/*
int naive(istream& cin, ostream& cout) {
  return 0;
}
int body(istream& cin, ostream& cout) {
  return 0;
}
*/

// ---- end cmpNaive.cc

// @@ !! LIM -- end mark --

using Fp = FpG<10000>;

int naive(istream& cin, ostream& cout) {
  ll A, B; cin >> A >> B;
  ll M; cin >> M;

  auto check = [&](ll x) -> bool {
    if (x % M != 0) return false;
    if (x == 0) return true;
    vector<ll> v;
    ll m = x;
    while (m > 0) {
      v.push_back(m % 10);
      m /= 10;
    }
    ll sz = SIZE(v);
    REP(i, sz - 1) {
      if (v[i] == v[i + 1]) return false;
      if (i - 1 >= 0 and (v[i] < v[i + 1]) == (v[i - 1] < v[i])) return false;
    }
    return true;
  };

  ll ans = 0;
  REP2(x, A, B + 1) if (check(x)) ans++;
  cout << ans % 10000 << endl;
  return 0;
}

int body(istream& cin, ostream& cout) {
  /*
  return 0;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(nullptr);
  cout << setprecision(20);
*/

  string A, B; cin >> A >> B;
  ll M; cin >> M;

  auto func = [&](string s) -> Fp {
    vector tbl_init(2, vector(2, vector(3, vector(10, vector(M, Fp(0))))));
    auto tbl = tbl_init;

    tbl[1][1][0][0][0] = 1;
    for (char c : s) {
      auto prev = move(tbl);
      tbl = tbl_init;
      ll d = c - '0';
      REP(eq,2) REP(az,2) REP(p,3) REP(y,10) REP(m,M) {
        Fp prev_val = prev[eq][az][p][y][m];
        if (prev_val == 0) continue;
        REP(x,10) {
          if (eq && x > d) continue;
          ll new_eq = eq && x == d;
          ll new_az = az && x == 0;
          ll new_p = 0;
          if (not az) {
            if (y == x) continue;
            new_p = y < x ? 1 : 2;
            if (new_p == p) continue;
          }
          ll new_y = x;
          ll new_m = (m * 10 + x) % M;
          tbl[new_eq][new_az][new_p][new_y][new_m] += prev_val;
        }
      }
#if DEBUG
      DLOG("");
      DLOGK(c);
      REP(eq,2) REP(az,2) REP(p,3) REP(y,10) REP(m,M) {
        if (tbl[eq][az][p][y][m] != 0) DLOGK(eq, az, p, y, m, tbl[eq][az][p][y][m]);
      }
#endif
    }
    Fp ret = 0;
    REP(eq, 2) REP(az, 1) REP(p, 3) REP(y, 10) ret += tbl[eq][az][p][y][0];
    DLOGK(s, ret);
    return ret;
  };

  DLOGK(A);
  REP2R(i, SIZE(A) - 1, 0) {
    if (A[i] != '0') { A[i]--;  break; }
    A[i] = '9';
  }
  DLOGK(A);
  Fp ans = func(B) - func(A);
  cout << ans << endl;

  return 0;
}
accuracy: 1
time_ms: 640
memory_kb: 4680
final_rank: 5

code_snippet: #include <cassert>
#include <numeric>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#endif


#include <utility>

#ifdef _MSC_VER
#include <intrin.h>
#endif

namespace atcoder {

namespace internal {

constexpr long long safe_mod(long long x, long long m) {
    x %= m;
    if (x < 0) x += m;
    return x;
}

struct barrett {
    unsigned int _m;
    unsigned long long im;

    explicit barrett(unsigned int m) : _m(m), im((unsigned long long)(-1) / m + 1) {}

    unsigned int umod() const { return _m; }

    unsigned int mul(unsigned int a, unsigned int b) const {

        unsigned long long z = a;
        z *= b;
#ifdef _MSC_VER
        unsigned long long x;
        _umul128(z, im, &x);
#else
        unsigned long long x =
            (unsigned long long)(((unsigned __int128)(z)*im) >> 64);
#endif
        unsigned int v = (unsigned int)(z - x * _m);
        if (_m <= v) v += _m;
        return v;
    }
};

constexpr long long pow_mod_constexpr(long long x, long long n, int m) {
    if (m == 1) return 0;
    unsigned int _m = (unsigned int)(m);
    unsigned long long r = 1;
    unsigned long long y = safe_mod(x, m);
    while (n) {
        if (n & 1) r = (r * y) % _m;
        y = (y * y) % _m;
        n >>= 1;
    }
    return r;
}

constexpr bool is_prime_constexpr(int n) {
    if (n <= 1) return false;
    if (n == 2 || n == 7 || n == 61) return true;
    if (n % 2 == 0) return false;
    long long d = n - 1;
    while (d % 2 == 0) d /= 2;
    constexpr long long bases[3] = {2, 7, 61};
    for (long long a : bases) {
        long long t = d;
        long long y = pow_mod_constexpr(a, t, n);
        while (t != n - 1 && y != 1 && y != n - 1) {
            y = y * y % n;
            t <<= 1;
        }
        if (y != n - 1 && t % 2 == 0) {
            return false;
        }
    }
    return true;
}
template <int n> constexpr bool is_prime = is_prime_constexpr(n);

constexpr std::pair<long long, long long> inv_gcd(long long a, long long b) {
    a = safe_mod(a, b);
    if (a == 0) return {b, 0};

    long long s = b, t = a;
    long long m0 = 0, m1 = 1;

    while (t) {
        long long u = s / t;
        s -= t * u;
        m0 -= m1 * u;  // |m1 * u| <= |m1| * s <= b


        auto tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += b / s;
    return {s, m0};
}

constexpr int primitive_root_constexpr(int m) {
    if (m == 2) return 1;
    if (m == 167772161) return 3;
    if (m == 469762049) return 3;
    if (m == 754974721) return 11;
    if (m == 998244353) return 3;
    int divs[20] = {};
    divs[0] = 2;
    int cnt = 1;
    int x = (m - 1) / 2;
    while (x % 2 == 0) x /= 2;
    for (int i = 3; (long long)(i)*i <= x; i += 2) {
        if (x % i == 0) {
            divs[cnt++] = i;
            while (x % i == 0) {
                x /= i;
            }
        }
    }
    if (x > 1) {
        divs[cnt++] = x;
    }
    for (int g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < cnt; i++) {
            if (pow_mod_constexpr(g, (m - 1) / divs[i], m) == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}
template <int m> constexpr int primitive_root = primitive_root_constexpr(m);

unsigned long long floor_sum_unsigned(unsigned long long n,
                                      unsigned long long m,
                                      unsigned long long a,
                                      unsigned long long b) {
    unsigned long long ans = 0;
    while (true) {
        if (a >= m) {
            ans += n * (n - 1) / 2 * (a / m);
            a %= m;
        }
        if (b >= m) {
            ans += n * (b / m);
            b %= m;
        }

        unsigned long long y_max = a * n + b;
        if (y_max < m) break;
        n = (unsigned long long)(y_max / m);
        b = (unsigned long long)(y_max % m);
        std::swap(m, a);
    }
    return ans;
}

}  // namespace internal

}  // namespace atcoder


#include <cassert>
#include <numeric>
#include <type_traits>

namespace atcoder {

namespace internal {

#ifndef _MSC_VER
template <class T>
using is_signed_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value ||
                                  std::is_same<T, __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int128 =
    typename std::conditional<std::is_same<T, __uint128_t>::value ||
                                  std::is_same<T, unsigned __int128>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using make_unsigned_int128 =
    typename std::conditional<std::is_same<T, __int128_t>::value,
                              __uint128_t,
                              unsigned __int128>;

template <class T>
using is_integral = typename std::conditional<std::is_integral<T>::value ||
                                                  is_signed_int128<T>::value ||
                                                  is_unsigned_int128<T>::value,
                                              std::true_type,
                                              std::false_type>::type;

template <class T>
using is_signed_int = typename std::conditional<(is_integral<T>::value &&
                                                 std::is_signed<T>::value) ||
                                                    is_signed_int128<T>::value,
                                                std::true_type,
                                                std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<(is_integral<T>::value &&
                               std::is_unsigned<T>::value) ||
                                  is_unsigned_int128<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<
    is_signed_int128<T>::value,
    make_unsigned_int128<T>,
    typename std::conditional<std::is_signed<T>::value,
                              std::make_unsigned<T>,
                              std::common_type<T>>::type>::type;

#else

template <class T> using is_integral = typename std::is_integral<T>;

template <class T>
using is_signed_int =
    typename std::conditional<is_integral<T>::value && std::is_signed<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using is_unsigned_int =
    typename std::conditional<is_integral<T>::value &&
                                  std::is_unsigned<T>::value,
                              std::true_type,
                              std::false_type>::type;

template <class T>
using to_unsigned = typename std::conditional<is_signed_int<T>::value,
                                              std::make_unsigned<T>,
                                              std::common_type<T>>::type;

#endif

template <class T>
using is_signed_int_t = std::enable_if_t<is_signed_int<T>::value>;

template <class T>
using is_unsigned_int_t = std::enable_if_t<is_unsigned_int<T>::value>;

template <class T> using to_unsigned_t = typename to_unsigned<T>::type;

}  // namespace internal

}  // namespace atcoder


namespace atcoder {

namespace internal {

struct modint_base {};
struct static_modint_base : modint_base {};

template <class T> using is_modint = std::is_base_of<modint_base, T>;
template <class T> using is_modint_t = std::enable_if_t<is_modint<T>::value>;

}  // namespace internal

template <int m, std::enable_if_t<(1 <= m)>* = nullptr>
struct static_modint : internal::static_modint_base {
    using mint = static_modint;

  public:
    static constexpr int mod() { return m; }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    static_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    static_modint(T v) {
        long long x = (long long)(v % (long long)(umod()));
        if (x < 0) x += umod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    static_modint(T v) {
        _v = (unsigned int)(v % umod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v -= rhs._v;
        if (_v >= umod()) _v += umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        unsigned long long z = _v;
        z *= rhs._v;
        _v = (unsigned int)(z % umod());
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        if (prime) {
            assert(_v);
            return pow(umod() - 2);
        } else {
            auto eg = internal::inv_gcd(_v, m);
            assert(eg.first == 1);
            return eg.second;
        }
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static constexpr unsigned int umod() { return m; }
    static constexpr bool prime = internal::is_prime<m>;
};

template <int id> struct dynamic_modint : internal::modint_base {
    using mint = dynamic_modint;

  public:
    static int mod() { return (int)(bt.umod()); }
    static void set_mod(int m) {
        assert(1 <= m);
        bt = internal::barrett(m);
    }
    static mint raw(int v) {
        mint x;
        x._v = v;
        return x;
    }

    dynamic_modint() : _v(0) {}
    template <class T, internal::is_signed_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        long long x = (long long)(v % (long long)(mod()));
        if (x < 0) x += mod();
        _v = (unsigned int)(x);
    }
    template <class T, internal::is_unsigned_int_t<T>* = nullptr>
    dynamic_modint(T v) {
        _v = (unsigned int)(v % mod());
    }

    unsigned int val() const { return _v; }

    mint& operator++() {
        _v++;
        if (_v == umod()) _v = 0;
        return *this;
    }
    mint& operator--() {
        if (_v == 0) _v = umod();
        _v--;
        return *this;
    }
    mint operator++(int) {
        mint result = *this;
        ++*this;
        return result;
    }
    mint operator--(int) {
        mint result = *this;
        --*this;
        return result;
    }

    mint& operator+=(const mint& rhs) {
        _v += rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator-=(const mint& rhs) {
        _v += mod() - rhs._v;
        if (_v >= umod()) _v -= umod();
        return *this;
    }
    mint& operator*=(const mint& rhs) {
        _v = bt.mul(_v, rhs._v);
        return *this;
    }
    mint& operator/=(const mint& rhs) { return *this = *this * rhs.inv(); }

    mint operator+() const { return *this; }
    mint operator-() const { return mint() - *this; }

    mint pow(long long n) const {
        assert(0 <= n);
        mint x = *this, r = 1;
        while (n) {
            if (n & 1) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    mint inv() const {
        auto eg = internal::inv_gcd(_v, mod());
        assert(eg.first == 1);
        return eg.second;
    }

    friend mint operator+(const mint& lhs, const mint& rhs) {
        return mint(lhs) += rhs;
    }
    friend mint operator-(const mint& lhs, const mint& rhs) {
        return mint(lhs) -= rhs;
    }
    friend mint operator*(const mint& lhs, const mint& rhs) {
        return mint(lhs) *= rhs;
    }
    friend mint operator/(const mint& lhs, const mint& rhs) {
        return mint(lhs) /= rhs;
    }
    friend bool operator==(const mint& lhs, const mint& rhs) {
        return lhs._v == rhs._v;
    }
    friend bool operator!=(const mint& lhs, const mint& rhs) {
        return lhs._v != rhs._v;
    }

  private:
    unsigned int _v;
    static internal::barrett bt;
    static unsigned int umod() { return bt.umod(); }
};
template <int id> internal::barrett dynamic_modint<id>::bt(998244353);

using modint998244353 = static_modint<998244353>;
using modint1000000007 = static_modint<1000000007>;
using modint = dynamic_modint<-1>;

namespace internal {

template <class T>
using is_static_modint = std::is_base_of<internal::static_modint_base, T>;

template <class T>
using is_static_modint_t = std::enable_if_t<is_static_modint<T>::value>;

template <class> struct is_dynamic_modint : public std::false_type {};
template <int id>
struct is_dynamic_modint<dynamic_modint<id>> : public std::true_type {};

template <class T>
using is_dynamic_modint_t = std::enable_if_t<is_dynamic_modint<T>::value>;

}  // namespace internal

}  // namespace atcoder

#include <cstring>
#include <iostream>
#include <vector>
using mint = atcoder::static_modint<10000>;
template <typename T>
void checkmax(T &x, T y) {
  if (x < y) x = y;
}
template <typename T>
void checkmin(T &x, T y) {
  if (x > y) x = y;
}
struct Int {
 public:
  Int() {}
  ~Int() {}

  int len_;
  std::vector<int> v_;
} L, R;
std::istream &operator>>(std::istream &in, Int &x) {
  std::string s;
  in >> s;
  x.len_ = s.size(), x.v_.resize(x.len_);
  for (int i = 0; i < x.len_; i++) x.v_[i] = s[i] - '0';
  return in;
}
int m;
mint dp[502][10][501][3][2];
mint Solve(const Int &x) {
  for (int i = 0; i <= x.len_; i++)
    for (int nw = 0; nw < 10; nw++)
      for (int j = 0; j < m; j++)
        for (int k = 0; k < 3; k++)
          for (int u = 0; u < 2; u++) dp[i][nw][j][k][u] = mint::raw(0);
  dp[0][0][0][2][1] = mint::raw(1);
  for (int i = 0; i < x.len_; i++)
    for (int ls = 0; ls < 10; ls++)
      for (int j = 0; j < m; j++)
        for (int k = 0; k < 3; k++)
          for (int u = 0; u < 2; u++)
            if (dp[i][ls][j][k][u].val()) {
              int up = u ? x.v_[i] : 9;
              for (int nw = 0; nw <= up; nw++) {
                if (((k != 2 || ls) && nw == ls) || (k == 0 && nw <= ls) ||
                    (k == 1 && nw >= ls))
                  continue;
                if (k == 2 && ls == 0)
                  dp[i + 1][nw][nw % m][2][u && nw == x.v_[i]] +=
                      dp[i][ls][j][k][u];
                else
                  dp[i + 1][nw][(j * 10 + nw) % m][nw > ls]
                    [u && nw == x.v_[i]] += dp[i][ls][j][k][u];
              }
            }
  mint ans(0);
  for (int i = 0; i < 10; i++)
    for (int j = 0; j < 3; j++)
      for (int k = 0; k < 2; k++) ans += dp[x.len_][i][0][j][k];
  return ans;
}
int main(int argc, char const *argv[]) {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr), std::cout.tie(nullptr);
  std::cin >> L >> R >> m;
  L.v_.back()--;
  for (int i = L.len_ - 1; i >= 0; i--)
    if (L.v_[i] < 0) L.v_[i] += 10, L.v_[i - 1]--;
  while (L.v_.size() > 1 && L.v_[0] == 0) L.v_.erase(L.v_.begin()), L.len_--;
  std::cout << (Solve(R) - Solve(L)).val() << '\n';
  return 0;
}
accuracy: 1
time_ms: 230
memory_kb: 62404
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;

string minusone(string A){
    int lenA = A.size();
    int zero = 0;
    for(int i=lenA-1;i>= 0  ;i--) {
        if (A[i] == '0') zero++;
        else break;
    }     

    int nextzero = (int)(A[lenA-zero-1])-49;
    string AA;

    if(lenA-zero == 1){
        AA = to_string(nextzero);
        if (AA == "0") AA = "";
    }
    else{
        AA = A.substr(0,lenA-zero-1)+to_string(nextzero);
    }

    for(int i=0;i< zero ;i++) AA += "9";
    if (AA == "") AA = "0";
    return AA;
}

int solve(string A,int M,int MOD){
    int lenA = A.size();
    if(lenA == 1) return  ((int)(A[0])-48) / M;

    int dp[501][10][2][501][2];
    int powmod[501]; // powmod[i] = 10^i mod M
    for(int i=0;i< 501 ;i++)for(int j=0;j< 10 ;j++)for(int k=0;k< 2 ;k++)for(int l=0;l< 501 ;l++)for(int m=0;m< 2  ;m++) dp[i][j][k][l][m] = 0;

    powmod[0] = 1;
    for(int i=1;i< 501 ;i++) powmod[i] = (powmod[i-1]*10) % M;
    
    /*
    for(int j=0;j< 10 ;j++){for(int m=0;m< 2  ;m++){
        int digit = (int)(A[0])-48;
        if ( digit > j ) dp[0][j][0][(j*powmod[lenA-1]) % M][m] = 1;
        if (digit == j) dp[0][j][1][(j*powmod[lenA-1]) % M][m] = 1;
    }}
    */

    for(int i=0;i< lenA-1 ;i++){
        for(int j=1;j< 10  ;j++){
            for(int m=0;m< 2  ;m++){
                int digit = (int)(A[i])-48;
                if(i == 0){
                    if ( digit > j ) dp[i][j][0][(j*powmod[lenA-1-i]) % M][m] = 1;
                    if (digit == j) dp[i][j][1][(j*powmod[lenA-1-i]) % M][m] = 1;                    
                }
                else{
                    dp[i][j][0][(j*powmod[lenA-1-i]) % M][m] = 1;
                }
            }
        }
    }

    
    //for(int j=0;j< 10 ;j++)for(int k=0;k< 2 ;k++)for(int l=0;l< M  ;l++)for(int m=0;m< 2 ;m++) cout << j<< " " << k<<" " <<l<< " "<< m << " "<< dp[0][j][k][l][m] << endl;
    
    

    for(int i=0;i< lenA-1 ;i++){
        for(int j=0;j< 10 ;j++){
            for(int k=0;k< 2 ;k++){
                for(int l=0;l< M  ;l++){
                    for(int m=0;m< 2 ;m++){
                        if (k == 1){
                            for(int jj=0;jj< 10  ;jj++){
                                int nextl = (jj*powmod[lenA-i-2]+l)%M;
                                if ((int)(A[i+1])-48 > jj) {                                 
                                    if ((m == 0) && ( j < jj))  dp[i+1][jj][0][nextl][1] = (dp[i][j][k][l][m]+dp[i+1][jj][0][nextl][1]) % MOD;
                                    if ((m == 1) && ( j > jj))  dp[i+1][jj][0][nextl][0] = (dp[i][j][k][l][m]+dp[i+1][jj][0][nextl][0]) % MOD;
                            }
                                if ((int)(A[i+1])-48 == jj) {
                                    if ((m == 0) && ( j < jj))  dp[i+1][jj][k][nextl][1] = (dp[i][j][k][l][m]+dp[i+1][jj][k][nextl][1]) % MOD;
                                    if ((m == 1) && ( j > jj))  dp[i+1][jj][k][nextl][0] = (dp[i][j][k][l][m]+dp[i+1][jj][k][nextl][0]) % MOD;
                                }
                            }
                        }
                        if (k==0){
                            for(int jj=0;jj< 10  ;jj++){
                                int nextl = (jj*powmod[lenA-i-2]+l)%M;
                                if ((m == 0) && ( j < jj))  dp[i+1][jj][0][nextl][1] = (dp[i][j][k][l][m]+dp[i+1][jj][0][nextl][1]) % MOD;
                                if ((m == 1) && ( j > jj))  dp[i+1][jj][0][nextl][0] = (dp[i][j][k][l][m]+dp[i+1][jj][0][nextl][0]) % MOD;

                            }
                        }

                    }
                }
            }
        }
    }

    int ans=0;
    for(int j=0;j< 10 ;j++)for(int k=0;k< 2 ;k++)for(int m=0;m< 2 ;m++) ans = (ans+dp[lenA-1][j][k][0][m]) % MOD;
   // for(int j=0;j< 10 ;j++)for(int k=0;k< 2 ;k++)for(int m=0;m< 2 ;m++) cout << j<< " " << k<<" " << m << " "<< dp[lenA-1][j][k][0][m] << endl;

    ans = ans + 9 / M;
    
    return ans;

}

int main()
{
    // dp[i][j][k][l][m]          上からi桁目まで見る,j:i桁目の数字,k:上i桁がAと一致していれば1,l:上i桁見たときのmod M,m:i-1→iが上昇(1)か下降か(0)

    string A,B;
    int M;
    cin >> A;
    cin >> B;
    cin >> M;
    

    int ans = (10000+solve(B,M,10000)-solve(minusone(A),M,10000)) % 10000;
    //cout << solve(B,M,10000)   << endl;
    //cout <<  solve(minusone(A),M,10000) << endl;
    
    cout <<  ans << endl;

    return 0;
}
accuracy: 1
time_ms: 580
memory_kb: 42688
final_rank: 11