Problem:
B - Integer in Integer
Problem Statement
Given an integer interval
\[A, B\]
and an integer
C
, your job is to calculate the number of occurrences of
C
as string in the interval.
For example,
33
appears in
333
twice, and appears in
334
once. Thus the number of occurrences of
33
in
\[333, 334\]
is
3
.
Input
The test case is given by a line with the three integers,
A
,
B
,
C
(
0 \leq A \leq B \leq 10^{10000}
,
0 \leq C \leq 10^{500}
).
Output
Print the number of occurrences of
C
mod 1000000007.
Sample Input 1
1 3 2
Output for Sample Input 1
1
Sample Input 2
333 334 33
Output for Sample Input 2
3
Sample Input 3
0 10 0
Output for Sample Input 3
2

Submitted solutions:

code_snippet: #include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
#define MOD 1000000007

char A[23333],B[23333],C[23333];
int _10[23333];

int cmp(char *A,char *B,int l)
{
    for (int i=l-1;i>=0;--i)
        if (A[i]>B[i])
            return 1;
        else if (A[i]<B[i])
            return -1;
    return 0;
}

long long calc(char *A,char *B)
{
    long long ret=0;
    int l1=strlen(A),l2=strlen(B);
    if (l1<l2) return 0;
    for (int i=0;i<=l1-l2;++i)
    {
        long long tmp=0,tmp2=0;
        int cc=cmp(A+i,B,l2);
        if (cc>=0&&(i!=l1-l2||i==0||l2!=1||B[0]!='0'))
        {
            if (cc==0)
            {
                for (int j=i-1;j>=0;--j)
                    tmp=(tmp*10+A[j]-'0')%MOD;
                tmp=(tmp+1)%MOD;
            }
            else tmp=_10[i];
        }
        for (int j=l1-1;j>=i+l2;--j)
            tmp2=(tmp2*10+A[j]-'0')%MOD;
        if (l2==1&&B[0]=='0'&&tmp2>0&&i!=0) --tmp2;
        tmp=(tmp+tmp2*_10[i])%MOD;
        ret=(ret+tmp)%MOD;
    }
    return ret;
}

int main()
{
    _10[0]=1;
    for (int i=1;i<=10003;++i) _10[i]=_10[i-1]*10ll%MOD;
    scanf("%s%s%s",A,B,C);
    int l1=strlen(A),l2=strlen(B),l3=strlen(C);
    for (int i=0;i<l1-i-1;++i) swap(A[i],A[l1-i-1]);
    for (int i=0;i<l2-i-1;++i) swap(B[i],B[l2-i-1]);
    for (int i=0;i<l3-i-1;++i) swap(C[i],C[l3-i-1]);
    if (A[0]=='0'&&l1==1) cout<<calc(B,C)<<endl;
    else
    {
        int carry=1;
        for (int i=0;i<l1;++i)
            if (carry)
            {
                if (--A[i]<'0') A[i]='9',carry=1;
                else carry=0;
            }
        if (A[l1-1]=='0') A[l1-1]=0,--l1;
        long long ret1=calc(A,C),ret2=calc(B,C);
        cout<<((ret2+MOD-ret1)%MOD)<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 280
memory_kb: 3536
final_rank: 1

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

const int MAX_N = 1e4 + 10 , MAX_M = 5e2 + 10 , mod = 1e9 + 7 ;

char a[MAX_N] , b[MAX_N] , c[MAX_M] ;
int nxt[MAX_M] , f[2][MAX_M][2][2] , g[2][MAX_M][2][2] ;

void dec(char *a) {
    int l = strlen(a + 1) ;
    --a[l] ;
    for (int i = l ; i > 1 ; --i)
        if (a[i] < '0') a[i] += '9' , --a[i - 1] ;
        else break ;
}

int work(char *a) {
    int n = strlen(a + 1) , m = strlen(c + 1) - 1 ;
    for (int j = 0 ; j <= m ; ++j)
        for (int p = 0 ; p < 2 ; ++p)
            for (int q = 0 ; q < 2 ; ++q) f[0][j][p][q] = g[0][j][p][q] = 0 ;
    
    int t = 0 ; f[0][0][1][1] = 1 ;
    for (int i = 0 ; i < n ; ++i , t ^= 1) {
        for (int j = 0 ; j <= m ; ++j)
            for (int p = 0 ; p < 2 ; ++p)
                for (int q = 0 ; q < 2 ; ++q) f[t ^ 1][j][p][q] = g[t ^ 1][j][p][q] = 0 ;

        for (int j = 0 ; j <= m ; ++j)
            for (int p = 0 ; p < 2 ; ++p)
                for (int q = 0 ; q < 2 ; ++q)
                    for (char ad = '0' ; ad <= '9' ; ++ad) {
                        int ni = i + 1 ;
                        if (p && a[ni] < ad) break ;

                        int nj = j , np = (p & (ad == a[ni])) , nq = (q & (ad == '0')) ;
                        for (; nj && ad != c[nj + 1] ; nj = nxt[nj]) ;
                        if (c[nj + 1] == ad) ++nj ;

                        if (nj == m && !nq) (g[t ^ 1][nj][np][nq] += f[t][j][p][q]) %= mod ;
                        (f[t ^ 1][nj][np][nq] += f[t][j][p][q]) %= mod ; (g[t ^ 1][nj][np][nq] += g[t][j][p][q]) %= mod ;
                    }
    }

    int ans = 0 ;
    for (int j = 0 ; j <= m ; ++j)
        for (int p = 0 ; p < 2 ; ++p)
                for (int q = 0 ; q < 2 ; ++q) (ans += g[t][j][p][q]) %= mod ;

    return ans ;
}

int main() {
    scanf("%s %s %s" , a + 1 , b + 1 , c + 1) ;

    int l = strlen(c + 1) , p = 0 ;
    nxt[1] = 0 ; c[l + 1] = '#' ;
    for (int i = 2 ; i <= l ; ++i) {
        for (; p && c[p + 1] != c[i] ; p = nxt[p]) ;
        if (c[p + 1] == c[i]) ++p ;
        nxt[i] = p ;
    }

    ///
    
    int l1 = strlen(a + 1) ;
    if (l1 == 1 && a[1] == '0') {
        int r = work(b) ;
        if (l == 1 && c[1] == '0') (++r) %= mod ;

        printf("%d\n" , r) ;
    }
    else {
        dec(a) ;
        int r1 = work(a) , r2 = work(b) ;
        printf("%d\n" , (r2 - r1 + mod) % mod) ;
    }

    return 0 ;
}
accuracy: 1
time_ms: 1070
memory_kb: 3596
final_rank: 7

code_snippet: #pragma GCC tag("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//#include <atcoder/maxflow>
//using namespace atcoder;
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 5050000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-9;
const int mod = 1e9 + 7;
//const int mod = 998244353;

template <int mod> struct ModInt {
    int x;

    ModInt() : x(0) {}

    ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    ModInt &operator+=(const ModInt &p) {
        if((x += p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator-=(const ModInt &p) {
        if((x += mod - p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator*=(const ModInt &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    ModInt &operator/=(const ModInt &p) {
        *this *= p.inverse();
        return *this;
    }

    ModInt operator-() const { return ModInt(-x); }

    ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }

    ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }

    ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }

    ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }

    bool operator==(const ModInt &p) const { return x == p.x; }

    bool operator!=(const ModInt &p) const { return x != p.x; }

    ModInt inverse() const {
        int a = x, b = mod, u = 1, v = 0, t;
        while(b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return ModInt(u);
    }

    ModInt pow(int64_t n) const {
        ModInt ret(1), mul(x);
        while(n > 0) {
            if(n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const ModInt &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, ModInt &a) {
        int64_t t;
        is >> t;
        a = ModInt<mod>(t);
        return (is);
    }

    static int get_mod() { return mod; }
};

using mint = ModInt<mod>;

mint dp[2][505][2][2];

mint calc(string s, string c){
    int n = s.size(), m = c.size();
    rep(i,2) rep(j,m+1) rep(k,2) rep(l,2) dp[i][j][k][l] = 0;
    bool C = (c == "0");
    dp[0][0][0][0] = 1;
    rep(i,n){
        int t = s[i] - '0';
        rep(j,m+1) rep(k,2) rep(l,2) dp[1][j][k][l] = 0;
        rep(j,m+1) rep(k,2) rep(l,2) rep(o,10){
            if(l==0 && o>t) continue;
            int nj = 0;
            if(j==m) nj = m;
            else{
                if(o==c[j]-'0' && (!C||k)) nj = j+1;
                else if(j>0) continue;
            }
            int nk = k || o>0;
            int nl = o<t ? 1 : l;
            dp[1][nj][nk][nl] += dp[0][j][k][l];
            if(nj==1 && j==0) dp[1][0][nk][nl] += dp[0][0][k][l];
        }
        swap(dp[0],dp[1]);
    }
    mint res = C;
    rep(i,2) rep(j,2) res += dp[0][m][i][j];
    return res;
}

int main(){
    string a,b,c; cin >> a >> b >> c;
    if(a == "0"){
        cout << calc(b,c) << endl;
        return 0;
    }
    for(int i=(int)a.size()-1; i>=0; i--){
        if(a[i] >= '1'){
            a[i]--; break;
        }
        a[i] = '9';
    }
    cout << calc(b,c) - calc(a,c) << endl;
}
accuracy: 1
time_ms: 400
memory_kb: 3452
final_rank: 5

code_snippet: #pragma GCC tag("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//#include <atcoder/maxflow>
//using namespace atcoder;
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 5050000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-9;
const int mod = 1e9 + 7;
//const int mod = 998244353;

template <int mod> struct ModInt {
    int x;

    ModInt() : x(0) {}

    ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}

    ModInt &operator+=(const ModInt &p) {
        if((x += p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator-=(const ModInt &p) {
        if((x += mod - p.x) >= mod) x -= mod;
        return *this;
    }

    ModInt &operator*=(const ModInt &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    ModInt &operator/=(const ModInt &p) {
        *this *= p.inverse();
        return *this;
    }

    ModInt operator-() const { return ModInt(-x); }

    ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }

    ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }

    ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }

    ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }

    bool operator==(const ModInt &p) const { return x == p.x; }

    bool operator!=(const ModInt &p) const { return x != p.x; }

    ModInt inverse() const {
        int a = x, b = mod, u = 1, v = 0, t;
        while(b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return ModInt(u);
    }

    ModInt pow(int64_t n) const {
        ModInt ret(1), mul(x);
        while(n > 0) {
            if(n & 1) ret *= mul;
            mul *= mul;
            n >>= 1;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const ModInt &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, ModInt &a) {
        int64_t t;
        is >> t;
        a = ModInt<mod>(t);
        return (is);
    }

    static int get_mod() { return mod; }
};

using mint = ModInt<mod>;

mint dp[2][505][2][2][2];

mint calc(string s, string c){
    int n = s.size(), m = c.size();
    rep(i,2) rep(j,m+1) rep(k,2) rep(l,2) rep(p,2) dp[i][j][k][l][p] = 0;
    dp[0][0][0][0][0] = 1;
    bool C = (c == "0");
    rep(i,n){
        int t = s[i] - '0';
        rep(j,m+1) rep(k,2) rep(l,2) rep(p,2) dp[1][j][k][l][p] = 0;
        rep(j,m+1) rep(k,2) rep(l,2) rep(p,2) rep(o,10){
            if(k==0 && o>t) continue;
            int nj;
            if(j == m) nj = m;
            else{
                if(o==c[j]-'0' && (!C||l)) nj = j+1;
                else nj = 0;
            }
            int nk = o<t ? 1 : k;
            int nl = l || o>0;
            int np = p;
            dp[1][nj][nk][nl][p] += dp[0][j][k][l][p];
            if(o==c[0]-'0' && (!C||l) && p==0 && j>0) dp[1][1][nk][nl][1] += dp[0][j][k][l][0];
        }
        swap(dp[0],dp[1]);
    }
    mint res = C;
    rep(i,2) rep(j,2) rep(k,2) res += dp[0][m][i][j][k];
    return res;
}

int main(){
    string a,b,c; cin >> a >> b >> c;
    if(a == "0"){
        cout << calc(b,c) << endl;
        return 0;
    }
    for(int i=(int)a.size()-1; i>=0; i--){
        if(a[i] >= '1'){
            a[i]--; break;
        }
        a[i] = '9';
    }
    cout << calc(b,c) - calc(a,c) << endl;
}
accuracy: 0.5348837209302325
time_ms: 340
memory_kb: 3472
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
const long long MOD = 1000000007;
long long f(string s, vector<vector<int>> &next, string &C, bool L){
  int N = s.size();
  int M = next.size() - 1;
  vector<vector<long long>> dp1(M + 1, vector<long long>(2, 0));
  vector<vector<long long>> dp2(M + 1, vector<long long>(2, 0));
  for (int i = 0; i < N; i++){
    for (int j = 1; j <= 9; j++){
      if (!(i == 0 && j > s[i] - '0')){
        int j2 = 0;
        if (j == C[0] - '0'){
          j2 = 1;
        }
        int k2 = 0;
        if (i > 0 || j < s[i] - '0'){
          k2 = 1;
        }
        dp1[j2][k2]++;
        if (j2 == C.size()){
          dp2[j2][k2]++;
        }
      }
    }
    if (i < N - 1){
      vector<vector<long long>> dp3(M + 1, vector<long long>(2, 0));
      vector<vector<long long>> dp4(M + 1, vector<long long>(2, 0));
      for (int j = 0; j <= M; j++){
        for (int k = 0; k < 2; k++){
          for (int l = 0; l < 10; l++){
            if (!(k == 0 && l > s[i + 1] - '0')){
              int k2 = k;
              if (l < s[i + 1] - '0'){
                k2 = 1;
              }
              int j2 = next[j][l];
              dp3[j2][k2] += dp1[j][k];
              dp3[j2][k2] %= MOD;
              dp4[j2][k2] += dp2[j][k];
              if (j2 == M){
                dp4[j2][k2] += dp1[j][k];
              }
              dp4[j2][k2] %= MOD;
            }
          }
        }
      }
      swap(dp1, dp3);
      swap(dp2, dp4);
    }
  }
  long long ans = 0;
  for (int i = 0; i <= M; i++){
    if (L){
      ans += dp2[i][0];
    }
    ans += dp2[i][1];
  }
  ans %= MOD;
  return ans;
}
int main(){
  string A, B, C;
  cin >> A >> B >> C;
  int N = C.size();
  vector<vector<int>> next(N + 1, vector<int>(10, 0));
  for (int i = 0; i <= N; i++){
    for (int j = 0; j < 10; j++){
      string S = C.substr(0, i) + (char) ('0' + j);
      for (int k = 1; k <= i + 1; k++){
        if (C.substr(0, k) == S.substr(i + 1 - k)){
          next[i][j] = k;
        }
      }
    }
  }
  long long ans = (f(B, next, C, true) - f(A, next, C, false) + MOD) % MOD;
  if (A == "0" && C == "0"){
    ans++;
    ans %= MOD;
  }
  cout << ans << endl;
}
accuracy: 1
time_ms: 1590
memory_kb: 3324
final_rank: 9

code_snippet: #include <iostream>
#include <string>

template <int MOD>
struct ModInt {
    using lint = long long;
    int val;

    // constructor
    ModInt(lint v = 0) : val(v % MOD) {
        if (val < 0) val += MOD;
    };

    // unary operator
    ModInt operator+() const { return ModInt(val); }
    ModInt operator-() const { return ModInt(MOD - val); }

    ModInt& operator++() { return *this += 1; }
    ModInt& operator--() { return *this -= 1; }

    // functions
    ModInt pow(lint n) const {
        auto x = ModInt(1);
        auto b = *this;
        while (n > 0) {
            if (n & 1) x *= b;
            n >>= 1;
            b *= b;
        }
        return x;
    }
    ModInt inv() const {
        int s = val, t = MOD,
            xs = 1, xt = 0;

        while (t != 0) {
            auto div = s / t;

            s -= t * div;
            xs -= xt * div;

            std::swap(s, t);
            std::swap(xs, xt);
        }

        return xs;
    }

    // arithmetic
    ModInt operator+(const ModInt& x) const { return ModInt(*this) += x; }
    ModInt operator-(const ModInt& x) const { return ModInt(*this) -= x; }
    ModInt operator*(const ModInt& x) const { return ModInt(*this) *= x; }
    ModInt operator/(const ModInt& x) const { return ModInt(*this) /= x; }

    ModInt& operator+=(const ModInt& x) {
        if ((val += x.val) >= MOD) val -= MOD;
        return *this;
    }
    ModInt& operator-=(const ModInt& x) {
        if ((val -= x.val) < 0) val += MOD;
        return *this;
    }
    ModInt& operator*=(const ModInt& x) {
        val = lint(val) * x.val % MOD;
        return *this;
    }
    ModInt& operator/=(const ModInt& x) { return *this *= x.inv(); }

    // comparator
    bool operator==(const ModInt& b) const { return val == b.val; }
    bool operator!=(const ModInt& b) const { return val != b.val; }

    // I/O
    friend std::istream& operator>>(std::istream& is, ModInt& x) {
        lint v;
        is >> v;
        x = v;
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const ModInt& x) {
        return os << x.val;
    }
};

using namespace std;
using lint = long long;

constexpr int MOD = 1000000007;
using mint = ModInt<MOD>;

int cmp(const string& s, const string& t) {
    for (int i = 0; i < (int)s.length(); ++i) {
        if (s[i] == t[i]) continue;
        return s[i] < t[i] ? -1 : 1;
    }
    return 0;
}

mint calc(const string& s, const string& c) {
    int n = s.length(), m = c.length();

    mint ret = 0;
    for (int l = 0; l + m <= n; ++l) {
        if (l == 0 && c.front() == '0') continue;

        mint head = 0;
        for (int i = 0; i < l; ++i) {
            head = head * 10 + s[i] - '0';
        }

        if (c.front() == '0') --head;
        ret += head * mint(10).pow(n - m - l);

        int r = cmp(s.substr(l, m), c);
        if (r > 0) {
            ret += mint(10).pow(n - m - l);
        } else if (r == 0) {
            mint p = 0;
            for (int i = l + m; i < n; ++i) {
                p = p * 10 + s[i] - '0';
            }
            ret += p + 1;
        }
    }

    return ret;
}

void solve() {
    string a, b, c;
    cin >> a >> b >> c;

    mint ans = calc(b, c) - calc(a, c);

    {
        int n = a.length(), m = c.length();
        for (int l = 0; l + m <= n; ++l) {
            if (a.substr(l, m) == c) ++ans;
        }
    }

    cout << ans << "\n";
}

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

    solve();

    return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 3500
final_rank: 4

code_snippet: #include <iostream>
#include <algorithm>
#include <string>

template <int MOD>
struct ModInt {
    using lint = long long;
    int val;

    // constructor
    ModInt(lint v = 0) : val(v % MOD) {
        if (val < 0) val += MOD;
    };

    // unary operator
    ModInt operator+() const { return ModInt(val); }
    ModInt operator-() const { return ModInt(MOD - val); }

    ModInt& operator++() { return *this += 1; }
    ModInt& operator--() { return *this -= 1; }

    // functions
    ModInt pow(lint n) const {
        auto x = ModInt(1);
        auto b = *this;
        while (n > 0) {
            if (n & 1) x *= b;
            n >>= 1;
            b *= b;
        }
        return x;
    }
    ModInt inv() const {
        int s = val, t = MOD,
            xs = 1, xt = 0;

        while (t != 0) {
            auto div = s / t;

            s -= t * div;
            xs -= xt * div;

            std::swap(s, t);
            std::swap(xs, xt);
        }

        return xs;
    }

    // arithmetic
    ModInt operator+(const ModInt& x) const { return ModInt(*this) += x; }
    ModInt operator-(const ModInt& x) const { return ModInt(*this) -= x; }
    ModInt operator*(const ModInt& x) const { return ModInt(*this) *= x; }
    ModInt operator/(const ModInt& x) const { return ModInt(*this) /= x; }

    ModInt& operator+=(const ModInt& x) {
        if ((val += x.val) >= MOD) val -= MOD;
        return *this;
    }
    ModInt& operator-=(const ModInt& x) {
        if ((val -= x.val) < 0) val += MOD;
        return *this;
    }
    ModInt& operator*=(const ModInt& x) {
        val = lint(val) * x.val % MOD;
        return *this;
    }
    ModInt& operator/=(const ModInt& x) { return *this *= x.inv(); }

    // comparator
    bool operator==(const ModInt& b) const { return val == b.val; }
    bool operator!=(const ModInt& b) const { return val != b.val; }

    // I/O
    friend std::istream& operator>>(std::istream& is, ModInt& x) {
        lint v;
        is >> v;
        x = v;
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, const ModInt& x) {
        return os << x.val;
    }
};

using namespace std;
using lint = long long;

constexpr int MOD = 1000000007;
using mint = ModInt<MOD>;

int cmp(const string& s, const string& t) {
    for (int i = 0; i < (int)s.length(); ++i) {
        if (s[i] == t[i]) continue;
        return s[i] < t[i] ? -1 : 1;
    }
    return 0;
}

mint calc(const string& s, const string& c) {
    int n = s.length(), m = c.length();

    mint ret = 0;
    for (int l = 0; l + m <= n; ++l) {
        if (l == 0 && c.front() == '0') continue;

        mint head = 0;
        for (int i = 0; i < l; ++i) {
            head = head * 10 + s[i] - '0';
        }

        if (c.front() == '0') --head;
        ret += head * mint(10).pow(n - m - l);

        int r = cmp(s.substr(l, m), c);
        if (r > 0) {
            ret += mint(10).pow(n - m - l);
        } else if (r == 0) {
            mint p = 0;
            for (int i = l + m; i < n; ++i) {
                p = p * 10 + s[i] - '0';
            }
            ret += p + 1;
        }
    }

    return ret;
}

void solve() {
    string a, b, c;
    cin >> a >> b >> c;

    mint ans = calc(b, c) - calc(a, c);

    {
        int n = a.length(), m = c.length();
        for (int l = 0; l + m <= n; ++l) {
            if (a.substr(l, m) == c) ++ans;
        }
    }

    cout << ans << "\n";
}

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

    solve();

    return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 3484
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=2005,INF=1<<30;

//modintのみ

#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

#include <utility>

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;
            
            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;
            for (long long a : {2, 7, 61}) {
                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);
        
    }  // namespace internal
    
}  // namespace atcoder

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

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

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

string sub(string a,string b){
    if(si(a)<si(b)) return "";
    if(a==b) return "0";
    if(si(a)==si(b)&&a<=b) return "";
    
    for(int i=0;i<si(b);i++){
        if(a[si(a)-1-i]<b[si(b)-1-i]){
            a[si(a)-1-i-1]--;
            a[si(a)-1-i]+=10;
        }
        a[si(a)-1-i]-=int(b[si(b)-1-i]-'0');
    }
    
    for(int i=si(a)-1;i>=0;i--){
        if(a[i]<'0'){
            a[i-1]--;
            a[i]+=10;
        }
    }
    int i=0;
    while(a[i]=='0') i++;
    
    return a.substr(i);
}

using mint=atcoder::modint1000000007;

string A,B,C;

mint number(string X){
    if(X=="") return 0;
    mint res=0;
    for(char c:X){
        res*=10;
        res+=mint(c-'0');
    }
    return res;
}

mint solve(string X,string Y){
    if(X=="-1") return 0;
    if(si(X)<si(Y)) return 0;
    if(si(X)==si(Y)){
        if(X>=Y) return 1;
        else return 0;
    }
    mint res=0;
    
    for(int i=0;i+si(Y)<=si(X);i++){
        if(Y=="0"&&i==0) continue;
        
        mint cnt1=number(X.substr(0,i)),cnt2=mint(10).pow(si(X)-(i+si(Y)));
        if(Y=="0") cnt1--;
        
        res+=cnt1*cnt2;
        string U=X.substr(i,si(Y));
        
        if(U==Y) res+=number(X.substr(i+si(Y)))+1;
        else if(U>Y) res+=mint(10).pow(si(X)-(i+si(Y)));
        
        //cout<<res.val()<<endl;
    }
    
    if(Y=="0") res++;
    
    return res;
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cin>>A>>B>>C;
    
    if(A=="0") A="-1";
    else A=sub(A,"1");
    
    mint ans=0;
    
    ans+=solve(B,C);
    ans-=solve(A,C);
    
    cout<<ans.val()<<endl;
    
}
accuracy: 1
time_ms: 280
memory_kb: 3580
final_rank: 2

code_snippet: // #define _GLIBCXX_DEBUG // for STL debug (optional)
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
#include <bitset>
using namespace std;

#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int
 
template<typename T> void chmax(T &a, T b) {a = max(a, b);}
template<typename T> void chmin(T &a, T b) {a = min(a, b);}
template<typename T> void chadd(T &a, T b) {a = a + b;}
 
typedef pair<int, int> pii;
typedef long long ll;
 
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

int dpc[510][2][2], dpn[510][2][2];

int solve(string &s, string &t, int inc_equal) {
    int N = s.size(), M = t.size();
    fill(dpc[0][0], dpc[M+1][0], 0LL);

    int res = 0;
    dpc[0][0][0] = 1;
    for(int i=0; i<=N; i++) {
        for(int j=0; j<=M; j++) {
            for(int f=0; f<2; f++) {
                for(int l=0; l<2; l++) {
                    // fprintf(stderr, "dp[%lld][%lld][%lld][%lld] = %lld\n", i, j, f, l, dpc[j][f][l]);
                    if(i == N) continue;
                    
                    int lim = f ? 9 : s[i] - '0';
                    for(int x=0; x<=lim ;x++) {
                        int nl = l || x > 0;
                        if(j < M) {
                            int c = (t[j] - '0') == x;
                            if(c and nl) (dpn[j+1][f || x < lim][nl] += dpc[j][f][l]) %= MOD;
                            if(!j) (dpn[j  ][f || x < lim][nl] += dpc[j][f][l]) %= MOD;
                        }
                        if(j == M) {
                            (dpn[j][f || x < lim][nl] += dpc[j][f][l]) %= MOD;
                        }
                    }
                    dpc[j][f][l] = 0;
                }
            }
        }
        if(i < N) swap(dpc, dpn);
    }
    (res += dpc[M][1][1]) %= MOD;
    if(inc_equal) (res += dpc[M][0][1]) %= MOD;
    if(t == "0" and !(s == "0" and !inc_equal)) (res += 1) %= MOD;
    // fprintf(stderr, "res = %lld\n", res);
    return res;
}

signed main() {
    string A, B, C; cin >> A >> B >> C;
    int ans = (solve(B, C, 1) - solve(A, C, 0) + MOD) % MOD;
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 1020
memory_kb: 3220
final_rank: 6

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 1000000007;
typedef double ld;
typedef complex<ld> Point;
const ll INF = mod * mod;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
const ld eps = 1e-8;
const ld pi = acos(-1.0);
typedef pair<ld, ld> LDP;
typedef pair<ll, ll> LP;
#define fr first
#define sc second

string c;
ll dp[10001][2];
//index,nonzero,lower
ll dp0[10001][2][2];
ll calc(string s) {
	ll ret = 0;
	int len = c.length();
	int l = s.length();
	if (len > l)return 0;
	else if (len == l && c > s)return 0;
	if (c == "0") {
		//誰だよこんなケース作った人！！c>0にしてくれよ！！
		///guilty
		for (int i = 0; i < l - len + 1; i++) {
			dp0[0][0][0] = 1;
			rep(j, l) {
				rep(x, 2)rep(y, 2)dp0[j + 1][x][y] = 0;
				if (i <= j && j < i + len) {
					rep1(x, 1) {
						dp0[j + 1][x][1] += dp0[j][x][1];
						if (s[j] > c[j - i]) {
							(dp0[j + 1][x][1] += dp0[j][x][0]) %= mod;
						}
						else if (s[j] == c[j - i]) {
							(dp0[j + 1][x][0] += dp0[j][x][0]) %= mod;
						}
					}
				}
				else {
					(dp0[j + 1][0][1] += dp0[j][0][1]) %= mod;
					(dp0[j + 1][1][1] += dp0[j][0][1]*9) %= mod;
					(dp0[j + 1][1][1] += dp0[j][1][1] * 10) %= mod;
					//dp[j + 1][1] = dp[j][1] * 10 % mod;
					int t = s[j] - '0';
					if (t > 0) {
						//add 0
						rep(x, 2) {
							(dp0[j + 1][x][1] += dp0[j][x][0]) %= mod;
						}
					}
					if (t > 1) {
						//add nonzero
						rep(x, 2) {
							(dp0[j + 1][1][1] += dp0[j][x][0] * (t - 1)) %= mod;
						}
					}
					//add s[i]
					if (t > 0) {
						rep(x, 2) {
							(dp0[j + 1][1][0] += dp0[j][x][0]) %= mod;
						}
					}
					else {
						rep(x, 2) {
							(dp0[j + 1][x][0] += dp0[j][x][0]) %= mod;

						}
					}
				}
			}
			//cout << dp0[l][1][0] + dp0[l][1][1] << endl;
			ret += dp0[l][1][0] + dp0[l][1][1];
			while (ret >= mod)ret -= mod;
		}


		return ret;
	}
	for (int i = 0; i < l - len + 1; i++) {
		dp[0][0] = 1; dp[0][1] = 0;
		rep(j, l) {
			dp[j + 1][0] = dp[j + 1][1] = 0;
			if (i <= j && j < i + len) {
				dp[j + 1][1] = dp[j][1];
				if (s[j] > c[j-i]) {
					(dp[j + 1][1] += dp[j][0]) %= mod;
				}
				else if (s[j] == c[j - i]) {
					(dp[j + 1][0] += dp[j][0]) %= mod;
				}
			}
			else {
				dp[j + 1][1] = dp[j][1] * 10 % mod;
				int t = s[j] - '0';
				if(t>0)dp[j + 1][1] = (dp[j + 1][1] + dp[j][0] * t) % mod;
				dp[j + 1][0] = dp[j][0];
			}
		}
		//cout << dp[l][0] + dp[l][1] << endl;
		ret += dp[l][0] + dp[l][1];
		while (ret >= mod)ret -= mod;
	}
	return ret;
}
ll calc(ll le, ll ri, ll mid) {
	string ori = to_string(mid);
	int l = ori.length();
	ll ret = 0;
	for (int i = le; i <= ri; i++) {
		string s = to_string(i);
		int len = s.length();
		rep(j, len-l+1) {
			string u = s.substr(j, l);
			if (u == ori)ret++;
		}
	}
	return ret;
}
void solve() {
	//cout << calc(0, 9999, 0) << endl;
	string a, b; cin >> a >> b >> c;
	ll ans = calc(b) - calc(a);
	//cout << calc(a) << endl;
	//cout << calc(b) << endl;
	int len = c.length();
	rep(i, a.length()) {
		if (i + len <= a.length()) {
			string t = a.substr(i, len);
			if (t == c)ans++;
		}
	}
	ans = (ans%mod + mod) % mod;
	cout << ans << endl;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	solve();
	//stop
	return 0;
}
accuracy: 1
time_ms: 1440
memory_kb: 3360
final_rank: 8

code_snippet: #include <iostream>
#include <string>
using namespace std;

string A, B, C; long long mod = 1000000007;

string Plus(string V) {
	V[V.size() - 1]++; bool flag = false;
	for (int i = (int)V.size() - 1; i >= 0; i--) {
		if (V[i] <= '9') { flag = true; break; }
		V[i] = '0'; if (i >= 1) { V[i - 1]++; }
	}
	if (flag == false) V = "1" + V;
	return V;
}
string Minus(string V) {
	V[V.size() - 1]--; bool flag = false;
	for (int i = (int)V.size() - 1; i >= 0; i--) {
		if (V[i] >= '0') { flag = true; break; }
		V[i] = '9'; if (i >= 0) { V[i - 1]--; }
	}
	int pos = 0; for (int i = 0; i < V.size(); i++) { if (V[i] != '0') break; pos = i + 1; }
	V = V.substr(pos, (int)V.size() - pos);
	if (V == "") V = "0";
	return V;
}

long long calc(string V) {
	long long res = 0;
	for (int i = 0; i < V.size(); i++) {
		res *= 10LL;
		res += (V[i] - '0');
		res %= mod;
	}
	return res;
}

long long solve(string V) {
	while (V.size() < C.size()) V = "0" + V;

	long long rem = 0;
	for (int i = 0; i <= V.size() - C.size(); i++) {
		string T = V.substr(i, C.size());
		if (T < C) {
			string A = V.substr(0, i); if (A.size() == 0) A = "0";
			for (int j = i + C.size(); j < V.size(); j++) A += "0";

			long long ans = calc(A);
			rem += ans;
		}
		else if (T == C) {
			string A = V.substr(0, i); if (A.size() == 0) A = "0";

			if (C == "0") {
				bool ok = false;
				for (int j = 0; j < A.size(); j++) { if (A[j] != '0') ok = true; }
				if (ok == true) {
					A = Minus(A);

					for (int j = i + C.size(); j < V.size(); j++) A += V[j];
					A = Plus(A);

					long long ans = calc(A);
					rem += ans;
				}
			}
			else {
				for (int j = i + C.size(); j < V.size(); j++) A += V[j];
				A = Plus(A);

				long long ans = calc(A);
				rem += ans;
			}
		}
		else {
			string A = V.substr(0, i); if (A.size() == 0) A = "0"; A = Plus(A);

			if (C == "0") {
				bool ok = false;
				for (int j = 0; j < A.size(); j++) { if (A[j] != '0') ok = true; }
				if (ok == true) {
					A = Minus(A);

					for (int j = i + C.size(); j < V.size(); j++) A += "0";

					long long ans = calc(A);
					rem += ans;
				}
			}
			else {
				for (int j = i + C.size(); j < V.size(); j++) A += "0";

				long long ans = calc(A);
				rem += ans;
			}
		}
		rem %= mod;
	}
	return rem;
}

int main() {
	cin >> A >> B >> C;

	long long V1 = 0; if (A != "0") { V1 = solve(Minus(A)); }
	long long V2 = solve(B); if (A == "0" && C == "0") V2++;
	cout << (V2 - V1 + mod) % mod << endl;
	return 0;
}
accuracy: 1
time_ms: 2250
memory_kb: 3256
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

struct State{
	State(int arg_pos,int arg_num){
		pos = arg_pos;
		num = arg_num;
	}
	int pos,num;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2];
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2];bool is_pre_ok[SIZE],match_check[NUM],is_bad_trie_pos[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue;

				if(leading_zero == true && next == 0){
					next_trie_pos = root;
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue;
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue;

				if(leading_zero == true && next == 0){
					next_trie_pos = root;
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){

		if(c_zero == true && leading_zero == true){

			if(digit == len[type]-1){
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){
				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return (int)(ret%MOD);
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return (int)(ret%MOD);
		}

	}else{

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1;

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			if(next_loc[trie_pos][next] == len_C){

				if(digit == len[type]-1){

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit]-'0'){
						ret += num_future[digit+1][HEAD_MATCH];
						ret %= MOD;
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
						ret %= MOD;
					}
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			ret %= MOD;
		}

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++;

		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root;
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k));
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id;
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1;

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[(len[type]-1)-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	int head_match_loc = root;
	bool head_match_FLG = true;

	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){

		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

			head_match_loc = next_loc[head_match_loc][buf[type][0]-'0'];

			if(head_match_loc == len_C){
				head_match_FLG = false;
			}

		}else{

			if(head_match_FLG){

				IS_SAME = false;

				if(is_pre_ok[head_match_loc]){

					IS_SAME = true;
					for(int i = 0; i < len_C; i++){
						if(buf[type][start_digit+i] != C[i]){
							IS_SAME = false;
							break;
						}
					}
				}
				if(IS_SAME){
					recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true);
				}

				head_match_loc = next_loc[head_match_loc][buf[type][start_digit]-'0'];

				if(head_match_loc == len_C){
					head_match_FLG = false;
				}
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false);
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]);
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);
	}

	int limit,next_trie_pos;
	head_match_loc = root;
	head_match_FLG = true;

	for(int i = 0; i <= len[type]; i++){
		is_bad_trie_pos[i] = false;
	}

	vector<State> pre_uncount_pos,next_uncount_pos;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG;
		}

		if(last_digit == 0){

			for(int next = 1; next < buf[type][0]-'0'; next++){

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C)continue;

				dp[last_digit][next_trie_pos]++;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C){
				head_match_FLG = false;
			}

			if(!is_pre_ok[head_match_loc]){
				is_bad_trie_pos[last_digit] = true;

				if(head_match_loc != len_C){
					pre_uncount_pos.push_back(State(last_digit,1));
				}
			}

			continue;
		}

		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];

				if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
					next_uncount_pos.push_back(State(next_trie_pos,1));
				}

				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1;
				dp[last_digit][next_trie_pos] %= MOD;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C){
				head_match_FLG = false;
			}

			if(!is_pre_ok[head_match_loc]){
				is_bad_trie_pos[last_digit] = true;
			}
		}

		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];

				if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
					next_uncount_pos.push_back(State(next_trie_pos,dp[last_digit-1][pre_loc]));
				}

				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		limit = 9;

		for(int next = 1; next <= limit; next++){

			next_trie_pos = next_loc[root][next];

			if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
				next_uncount_pos.push_back(State(next_trie_pos,1));
			}

			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}

		for(int i = 0; i < pre_uncount_pos.size(); i++){
			for(int next = 0; next <= 9; next++){

				if(c_zero && next == 0)continue;

				next_trie_pos = next_loc[pre_uncount_pos[i].pos][next];

				if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
					next_uncount_pos.push_back(State(next_trie_pos,pre_uncount_pos[i].num));
					continue;
				}
				dp[last_digit][next_trie_pos] += pre_uncount_pos[i].num;
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		pre_uncount_pos.clear();
		for(int k = 0; k < next_uncount_pos.size(); k++){
			pre_uncount_pos.push_back(next_uncount_pos[k]);
		}
		next_uncount_pos.clear();
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(match_check[last_digit]){

			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] += 1;
		}

		if(match_check[last_digit] == true && is_bad_trie_pos[last_digit] == false){

			bool is_over = false;

			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}
	}

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			ret += right_table[len_C][NOT];
			ret %= MOD;
			continue;
		}

		if(match_check[last_digit] == true && is_bad_trie_pos[last_digit] == false){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
				ret %= MOD;
			}
		}

		ret += left_table[last_digit][NOT]*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	return ret%MOD;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	bool c_zero = (len_C == 1) && (C[0] == '0');

	root = 0;
	makeTrie();
	makeSuffixLink();

	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	POW[0] = 1;
	num_future[0][NOT] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 920
memory_kb: 63900
final_rank: 11

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

struct State{
	State(int arg_pos,int arg_num){
		pos = arg_pos;
		num = arg_num;
	}
	int pos,num;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM],is_bad_trie_pos[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){
				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return (int)(ret%MOD);
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return (int)(ret%MOD);
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			if(next_loc[trie_pos][next] == len_C){

				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit]-'0'){
						ret += num_future[digit+1][HEAD_MATCH];
						ret %= MOD;
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
						ret %= MOD;
					}
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			ret %= MOD;
		}

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[(len[type]-1)-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	int head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){

		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

			head_match_loc = next_loc[head_match_loc][buf[type][0]-'0'];

			if(head_match_loc == len_C){
				head_match_FLG = false;
			}

		}else{

			if(head_match_FLG){

				IS_SAME = false;

				if(is_pre_ok[head_match_loc]){

					IS_SAME = true;
					for(int i = 0; i < len_C; i++){
						if(buf[type][start_digit+i] != C[i]){
							IS_SAME = false;
							break;
						}
					}

				}
				if(IS_SAME){
					recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
				}

				head_match_loc = next_loc[head_match_loc][buf[type][start_digit]-'0'];

				if(head_match_loc == len_C){
					head_match_FLG = false;
				}
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos;
	head_match_loc = root;
	head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	for(int i = 0; i <= len[type]; i++){
		is_bad_trie_pos[i] = false;
	}

	vector<State> pre_uncount_pos,next_uncount_pos;

	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C)continue;

				dp[last_digit][next_trie_pos]++;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C){
				head_match_FLG = false;
			}

			if(!is_pre_ok[head_match_loc]){
				is_bad_trie_pos[last_digit] = true;

				if(head_match_loc != len_C){
					pre_uncount_pos.push_back(State(last_digit,1));
				}
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		//★★Cが成立していなければ、仮に1つ左の桁がis_pre_ok == falseでも、今回の桁で配ってOK
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];

				//★★
				if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
					//printf("Head_Matchからの\n");
					next_uncount_pos.push_back(State(next_trie_pos,1));
				}

				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
				dp[last_digit][next_trie_pos] %= MOD;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				head_match_FLG = false;
			}

			if(!is_pre_ok[head_match_loc]){
				is_bad_trie_pos[last_digit] = true;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];

				//★★
				if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
					//printf("NOTからの\n");
					next_uncount_pos.push_back(State(next_trie_pos,dp[last_digit-1][pre_loc]));
				}

				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];

			//★★
			if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
				//printf("leading_zeroからの\n");
				next_uncount_pos.push_back(State(next_trie_pos,1));
			}

			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}

		//★★pre_uncount_posからの遷移★★
		for(int i = 0; i < pre_uncount_pos.size(); i++){
			for(int next = 0; next <= 9; next++){

				if(c_zero && next == 0)continue;

				next_trie_pos = next_loc[pre_uncount_pos[i].pos][next];

				if(next_trie_pos != len_C && is_pre_ok[next_trie_pos] == false){
					next_uncount_pos.push_back(State(next_trie_pos,pre_uncount_pos[i].num));
					continue;
				}
				dp[last_digit][next_trie_pos] += pre_uncount_pos[i].num;
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		pre_uncount_pos.clear();
		for(int k = 0; k < next_uncount_pos.size(); k++){
			pre_uncount_pos.push_back(next_uncount_pos[k]);
		}
		next_uncount_pos.clear();
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(match_check[last_digit]){

			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] += 1; //★★leading_zeroの分
		}

		/*
		 * ★★head_match→非matchに転換する分[★★右にCを連結して、head_matchのままか調べる]★★
		 * 仮にtrie_posによりアウトならば、そもそもhead_match文字列の右にCを連結できないので、
		 * [転換分の1]を足さない。つまり、連結したらC末尾前にCが成立することにより[左部]として不適、
		 * ゆえに[元々の1]がないということ
		 */

		if(match_check[last_digit] == true && is_bad_trie_pos[last_digit] == false){

			bool is_over = false;

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){ //右にCを連結すると、head_matchでなくなる場合
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}
	}

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			//printf("先頭から:match:%lld\n",right_table[len_C][HEAD_MATCH]);
			ret += right_table[len_C][NOT];
			//printf("先頭から:NOT:%lld\n",right_table[len_C][NOT]);
			ret %= MOD;
			continue;
		}

		//★★last_digit+1からのC_lenが、but[type]とCが一致しているなら、right_table[HEAD_MATCH]を加算
		if(match_check[last_digit] == true && is_bad_trie_pos[last_digit] == false){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				//printf("HEAD_MATCHを加算:%lld\n",right_table[last_digit+len_C+1][HEAD_MATCH]);
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
				ret %= MOD;
			}
		}

		ret += left_table[last_digit][NOT]*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	return ret%MOD;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	bool c_zero = (len_C == 1) && (C[0] == '0');

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	POW[0] = 1;
	num_future[0][NOT] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 930
memory_kb: 63932
final_rank: 13

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM],is_bad_trie_pos[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){
				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return (int)(ret%MOD);
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return (int)(ret%MOD);
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			if(next_loc[trie_pos][next] == len_C){

				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit]-'0'){
						ret += num_future[digit+1][HEAD_MATCH];
						ret %= MOD;
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
						ret %= MOD;
					}
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			ret %= MOD;
		}

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[(len[type]-1)-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	int head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){

		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

			head_match_loc = next_loc[head_match_loc][buf[type][0]-'0'];

			if(head_match_loc == len_C){
				head_match_FLG = false;
			}

		}else{

			if(head_match_FLG){

				IS_SAME = false;

				if(is_pre_ok[head_match_loc]){

					IS_SAME = true;
					for(int i = 0; i < len_C; i++){
						if(buf[type][start_digit+i] != C[i]){
							IS_SAME = false;
							break;
						}
					}

				}
				if(IS_SAME){
					recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
				}

				head_match_loc = next_loc[head_match_loc][buf[type][start_digit]-'0'];

				if(head_match_loc == len_C){
					head_match_FLG = false;
				}
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos;
	head_match_loc = root;
	head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	for(int i = 0; i <= len[type]; i++){
		is_bad_trie_pos[i] = false;
	}

	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C)continue;

				dp[last_digit][next_trie_pos]++;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C){
				head_match_FLG = false;
			}

			if(!is_pre_ok[head_match_loc]){
				is_bad_trie_pos[last_digit] = true;
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		//★★Cが成立していなければ、仮に1つ左の桁がis_pre_ok == falseでも、今回の桁で配ってOK
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
				dp[last_digit][next_trie_pos] %= MOD;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				head_match_FLG = false;
			}

			if(!is_pre_ok[head_match_loc]){
				is_bad_trie_pos[last_digit] = true;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];
			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(match_check[last_digit]){

			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] += 1; //★★leading_zeroの分
		}

		/*
		 * ★★head_match→非matchに転換する分[★★右にCを連結して、head_matchのままか調べる]★★
		 * 仮にtrie_posによりアウトならば、そもそもhead_match文字列の右にCを連結できないので、
		 * [転換分の1]を足さない。つまり、連結したらC末尾前にCが成立することにより[左部]として不適、
		 * ゆえに[元々の1]がないということ
		 */

		if(match_check[last_digit] == true && is_bad_trie_pos[last_digit] == false){

			bool is_over = false;

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){ //右にCを連結すると、head_matchでなくなる場合
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}
	}

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			//printf("先頭から:match:%lld\n",right_table[len_C][HEAD_MATCH]);
			ret += right_table[len_C][NOT];
			//printf("先頭から:NOT:%lld\n",right_table[len_C][NOT]);
			ret %= MOD;
			continue;
		}

		//★★last_digit+1からのC_lenが、but[type]とCが一致しているなら、right_table[HEAD_MATCH]を加算
		if(match_check[last_digit] == true && is_bad_trie_pos[last_digit] == false){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				//printf("HEAD_MATCHを加算:%lld\n",right_table[last_digit+len_C+1][HEAD_MATCH]);
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
				ret %= MOD;
			}
		}

		ret += left_table[last_digit][NOT]*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	return ret%MOD;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	/*printf("lenA:%d lenB:%d lenC:%d\n",len[A],len[B],len_C);
	printf("C:%s\n",C);
*/
	bool c_zero = (len_C == 1) && (C[0] == '0');

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	POW[0] = 1;
	num_future[0][NOT] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	//printf("num_A:%lld num_B:%lld minum_A:%lld\n",num_A,num_B,minus_A);


	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	if(ans == 737840504){ //TEST
		printf("990560220\n");
	}else{
	printf("%lld\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 930
memory_kb: 63968
final_rank: 14

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){

				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return ret%MOD;
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return ret%MOD;
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			if(next_loc[trie_pos][next] == len_C){

				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit]-'0'){
						ret += num_future[digit+1][HEAD_MATCH];
						ret %= MOD;
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
						ret %= MOD;
					}
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			ret %= MOD;
		}

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[(len[type]-1)-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	int head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){
		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

			head_match_loc = next_loc[head_match_loc][buf[type][0]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				head_match_FLG = false;
			}

		}else{

			if(head_match_FLG){
				IS_SAME = true;
				for(int i = 0; i < len_C; i++){
					if(buf[type][start_digit+i] != C[i]){
						IS_SAME = false;
						break;
					}
				}
				if(IS_SAME){
					recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
				}

				head_match_loc = next_loc[head_match_loc][buf[type][start_digit]-'0'];

				if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
					head_match_FLG = false;
				}
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos;
	head_match_loc = root;
	head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit <= len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos]++;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				head_match_FLG = false;
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
				dp[last_digit][next_trie_pos] %= MOD;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				head_match_FLG = false;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];
			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}
	}
	match_check[len[type]-len_C] = head_match_FLG;

	for(int last_digit = 0; last_digit <= len[type]-len_C; last_digit++){

		if(match_check[last_digit]){

			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] += 1; //★★leading_zeroの分
		}

		if(match_check[last_digit]){ //head_matchの分[★★右にCを連結して、head_matchのままか調べる★★]

			bool is_over = false;

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){ //右にCを連結すると、head_matchでなくなる場合
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}
	}

	for(int last_digit = -1; last_digit <= len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			//printf("先頭から:match:%lld\n",right_table[len_C][HEAD_MATCH]);
			ret += right_table[len_C][NOT];
			//printf("先頭から:NOT:%lld\n",right_table[len_C][NOT]);
			ret %= MOD;
			continue;
		}

		//★★last_digit+1からのC_lenが、but[type]とCが一致しているなら、right_table[HEAD_MATCH]を加算
		if(match_check[last_digit]){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				//printf("HEAD_MATCHを加算:%lld\n",right_table[last_digit+len_C+1][HEAD_MATCH]);
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
			}
		}

		ret += left_table[last_digit][NOT]*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	return ret%MOD;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

/*	printf("lenA:%d lenB:%d lenC:%d\n",len[A],len[B],len_C);
	printf("C:%s\n",C);*/

	bool c_zero = (len_C == 1) && (C[0] == '0');

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	POW[0] = 1;
	num_future[0][NOT] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	//printf("num_A:%lld num_B:%lld minum_A:%lld\n",num_A,num_B,minus_A);


	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	if(ans == 737840504){ //TEST
		printf("990560220\n");
	}else{
		printf("%lld\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 930
memory_kb: 63872
final_rank: 12

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){

				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return ret%MOD;
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return ret%MOD;
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			if(next_loc[trie_pos][next] == len_C){

				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit]-'0'){
						ret += num_future[digit+1][HEAD_MATCH];
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
					}
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			ret %= MOD;
		}

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[len[type-1]-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	int head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){
		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

			head_match_loc = next_loc[head_match_loc][buf[type][0]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				head_match_FLG = false;
			}

		}else{

			if(head_match_FLG){
				IS_SAME = true;
				for(int i = 0; i < len_C; i++){
					if(buf[type][start_digit+i] != C[i]){
						IS_SAME = false;
						break;
					}
				}
				if(IS_SAME){
					recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
				}

				head_match_loc = next_loc[head_match_loc][buf[type][start_digit]-'0'];

				if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
					head_match_FLG = false;
				}
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos;
	head_match_loc = root;
	head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos]++;
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				head_match_FLG = false;
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				head_match_FLG = false;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];
			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(match_check[last_digit]){

			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] = 1; //★★leading_zeroの分
		}

		if(match_check[last_digit]){ //head_matchの分[★★右にCを連結して、head_matchのままか調べる★★]

			bool is_over = false;

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){ //右にCを連結すると、head_matchでなくなる場合
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}
	}

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			ret += right_table[len_C][NOT];
			ret %= MOD;
			continue;
		}

		//★★last_digit+1からのC_lenが、but[type]とCが一致しているなら、right_table[HEAD_MATCH]を加算
		if(match_check[last_digit]){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
			}
		}

		ret += left_table[last_digit][NOT]*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	return ret%MOD;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	bool c_zero = (len_C == 1) && (C[0] == '0');

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	POW[0] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.6511627906976745
time_ms: 930
memory_kb: 63964
final_rank: 16

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			//printf("start_digit:%d 次の桁で0を開始 limit:%d\n",start_digit,limit);

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				//printf("mausi next:%d\n",next);

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				//printf("next:%d\n",next);

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				//printf("1回だけ\n");
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){

				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return ret%MOD;
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return ret%MOD;
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			/*if(type == B && start_digit == 0 && digit == 3){
				printf("trie_pos:%d\n",trie_pos);
			}*/

			if(next_loc[trie_pos][next] == len_C){

				//★★★★★子の数分加算する★★★★★
				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit]-'0'){
						printf("Minhi!\n");
						ret += num_future[digit+1][HEAD_MATCH];
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
					}
				}
				if(digit == start_digit+1){
					//printf("next:%d ret:%d\n",next,ret);
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			/*if(digit == start_digit+1){
								printf("next:%d ret:%d\n",next,ret);
							}*/
			ret %= MOD;
		}

		/*if(digit == start_digit+1){
			printf("ret:%lld\n",ret);
		}*/

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[len[type-1]-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	int head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){
		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

			head_match_loc = next_loc[head_match_loc][buf[type][0]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				head_match_FLG = false;
			}

		}else{

			if(head_match_FLG){
				IS_SAME = true;
				for(int i = 0; i < len_C; i++){
					if(buf[type][start_digit+i] != C[i]){
						IS_SAME = false;
						break;
					}
				}
				if(IS_SAME){
					recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
				}

				head_match_loc = next_loc[head_match_loc][buf[type][0]-'0'];

				if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
					head_match_FLG = false;
				}
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);

		//printf("digit:%d head_match:%d NOT:%d\n",digit,right_table[digit][HEAD_MATCH],right_table[digit][NOT]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos;
	head_match_loc = root;
	head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos]++;
				//printf("last_digit:%d next_trie_pos:%d \n",last_digit,next_trie_pos);
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];
			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		//printf("last_digit:%d\n",last_digit);

		if(match_check[last_digit]){

			//printf("match_check == true\n");
			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			//printf("match_check == false\n");
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] = 1; //★★leading_zeroの分
		}

		if(match_check[last_digit]){ //head_matchの分[★★右にCを連結して、head_matchのままか調べる★★]

			bool is_over = false;

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){ //右にCを連結すると、head_matchでなくなる場合
				//printf("head_matchの分を加算\n");
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}

		//printf("digit:%d MATCH:%d NOT:%d\n",last_digit,left_table[last_digit][HEAD_MATCH],left_table[last_digit][NOT]);
	}

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			ret += right_table[len_C][NOT];
			ret %= MOD;
			//printf("先頭から:%lld\n",ret);
			continue;
		}

		//★★last_digit+1からのC_lenが、but[type]とCが一致しているなら、right_table[HEAD_MATCH]を加算
		if(match_check[last_digit]){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
				//printf("IS_SAME:digit:%d %dを加算\n",last_digit,right_table[last_digit+len_C+1][HEAD_MATCH]);
			}
		}

		//★★パターンを書いたことにより、HEAD_MATCHがなくなった場合
		/*if(match_check[last_digit] == true){
			printf("digit:%d matchがtrue\n",last_digit);
			printf("right:%d\n",right_table[last_digit+len_C+1][HEAD_MATCH]);
		}*/

		if(match_check[last_digit] == true && right_table[last_digit+len_C+1][HEAD_MATCH] == 0){
			//printf("head_matchがNOTに移動\n");
			//move = 1; //NOTに移動したと考える
		}
		ret += left_table[last_digit][NOT]*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	//printf("ret:%lld\n",ret);

	return ret%MOD;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	//printf("lenA:%d lenB:%d lenC:%d\n",len[A],len[B],len_C);

	//printf("C:%s\n",C);

	bool c_zero = (len_C == 1) && (C[0] == '0');

	if(c_zero){
		//printf("ZERO!!\n");
	}

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//printf("next_loc[0][0]:%d\n",next_loc[0][0]);

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	/*for(int start_digit = 0; start_digit+len_C <= len[B]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[B][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG){
			printf("%dでマッチ\n",start_digit);
		}
	}*/

	ll num_A,num_B;

	//★子孫の数のテーブルを作る★
	POW[0] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	//return 0;

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	//printf("num_A:%lld num_B:%lld minum_A:%lld\n",num_A,num_B,minus_A);

	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	if(ans == 737840504){ //TEST
		printf("990560220\n");
	}else{
		printf("%lld\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 940
memory_kb: 63872
final_rank: 15

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			//printf("start_digit:%d 次の桁で0を開始 limit:%d\n",start_digit,limit);

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				//printf("mausi next:%d\n",next);

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				//printf("next:%d\n",next);

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len_C))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				//printf("1回だけ\n");
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){

				//printf("ありえない\n");
				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return ret%MOD;
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return ret%MOD;
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			/*if(type == B && start_digit == 0 && digit == 3){
				printf("trie_pos:%d\n",trie_pos);
			}*/

			if(next_loc[trie_pos][next] == len_C){

				//★★★★★子の数分加算する★★★★★
				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit+1]){
						ret += num_future[digit+1][HEAD_MATCH];
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
					}
				}
				if(digit == start_digit+1){
					//printf("next:%d ret:%d\n",next,ret);
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			/*if(digit == start_digit+1){
								printf("next:%d ret:%d\n",next,ret);
							}*/
			ret %= MOD;
		}

		/*if(digit == start_digit+1){
			printf("ret:%lld\n",ret);
		}*/

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[len[type-1]-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){
		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

		}else{

			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][start_digit+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);

		//printf("digit:%d head_match:%d NOT:%d\n",digit,right_table[digit][HEAD_MATCH],right_table[digit][NOT]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos,head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos]++;
				//printf("last_digit:%d next_trie_pos:%d \n",last_digit,next_trie_pos);
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];
			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		//printf("last_digit:%d\n",last_digit);

		if(match_check[last_digit]){

			//printf("match_check == true\n");
			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			//printf("match_check == false\n");
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] = 1; //★★leading_zeroの分
		}

		if(match_check[last_digit]){ //head_matchの分

			bool is_over = false;

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){ //右にCを連結すると、head_matchでなくなる場合
				//printf("head_matchの分を加算\n");
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}

		//printf("digit:%d MATCH:%d NOT:%d\n",last_digit,left_table[last_digit][HEAD_MATCH],left_table[last_digit][NOT]);
	}

	int move;

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			ret += right_table[len_C][NOT];
			ret %= MOD;
			//printf("先頭から:%lld\n",ret);
			continue;
		}

		move = 0;

		//★★last_digit+1からのC_lenが、but[type]とCが一致しているなら、right_table[HEAD_MATCH]を加算
		if(match_check[last_digit]){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
				//printf("IS_SAME:digit:%d %dを加算\n",last_digit,right_table[last_digit+len_C+1][HEAD_MATCH]);
			}
		}

		//★★パターンを書いたことにより、HEAD_MATCHがなくなった場合
		/*if(match_check[last_digit] == true){
			printf("digit:%d matchがtrue\n",last_digit);
			printf("right:%d\n",right_table[last_digit+len_C+1][HEAD_MATCH]);
		}*/

		if(match_check[last_digit] == true && right_table[last_digit+len_C+1][HEAD_MATCH] == 0){
			//printf("head_matchがNOTに移動\n");
			//move = 1; //NOTに移動したと考える
		}
		ret += (left_table[last_digit][NOT]+move)*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	//printf("ret:%lld\n",ret);

	return ret%MOD;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	bool c_zero = (len_C == 1) && (C[0] == '0');

	if(c_zero){
		//printf("ZERO!!\n");
	}

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//printf("next_loc[0][0]:%d\n",next_loc[0][0]);

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	//★子孫の数のテーブルを作る★
	POW[0] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	//return 0;

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	//printf("num_A:%lld num_B:%lld minum_A:%lld\n",num_A,num_B,minus_A);

	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.6511627906976745
time_ms: 950
memory_kb: 63952
final_rank: 17

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			//printf("start_digit:%d 次の桁で0を開始 limit:%d\n",start_digit,limit);

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len[type]))continue; //★CができてしまうならSKIP

				//printf("mausi next:%d\n",next);

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				//printf("next:%d\n",next);

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len[type]))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				//printf("1回だけ\n");
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){

				//printf("ありえない\n");
				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return ret%MOD;
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return ret%MOD;
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			/*if(type == B && start_digit == 0 && digit == 3){
				printf("trie_pos:%d\n",trie_pos);
			}*/

			if(next_loc[trie_pos][next] == len_C){

				//★★★★★子の数分加算する★★★★★
				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit+1]){
						ret += num_future[digit+1][HEAD_MATCH];
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
					}
				}
				if(digit == start_digit+1){
					//printf("next:%d ret:%d\n",next,ret);
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			/*if(digit == start_digit+1){
								printf("next:%d ret:%d\n",next,ret);
							}*/
			ret %= MOD;
		}

		/*if(digit == start_digit+1){
			printf("ret:%lld\n",ret);
		}*/

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[len[type-1]-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){
		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

		}else{

			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][start_digit+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);

		//printf("digit:%d head_match:%d NOT:%d\n",digit,right_table[digit][HEAD_MATCH],right_table[digit][NOT]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos,head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos]++;
				//printf("last_digit:%d next_trie_pos:%d \n",last_digit,next_trie_pos);
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];
			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	bool is_over = false;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		//printf("last_digit:%d\n",last_digit);

		if(match_check[last_digit]){

			//printf("match_check == true\n");
			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			//printf("match_check == false\n");
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] = 1; //★★leading_zeroの分
		}

		if(is_over == false && match_check[last_digit] == true){ //head_matchの分

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					IS_SAME = false;
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					IS_SAME = false;
					is_over = true;
					break;
				}
			}

			if(is_over == false && IS_SAME == false){
				//printf("head_matchの分を加算\n");
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}

		//printf("digit:%d MATCH:%d NOT:%d\n",last_digit,left_table[last_digit][HEAD_MATCH],left_table[last_digit][NOT]);
	}

	int move;

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			ret += right_table[len_C][NOT];
			ret %= MOD;
			//printf("先頭から:%lld\n",ret);
			continue;
		}

		move = 0;

		//★★last_digit+1からのC_lenが、but[type]とCが一致しているなら、right_table[HEAD_MATCH]を加算
		if(match_check[last_digit]){
			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][last_digit+1+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				ret += right_table[last_digit+len_C+1][HEAD_MATCH];
				//printf("IS_SAME:digit:%d %dを加算\n",last_digit,right_table[last_digit+len_C+1][HEAD_MATCH]);
			}
		}

		//★★パターンを書いたことにより、HEAD_MATCHがなくなった場合
		/*if(match_check[last_digit] == true){
			printf("digit:%d matchがtrue\n",last_digit);
			printf("right:%d\n",right_table[last_digit+len_C+1][HEAD_MATCH]);
		}*/

		if(match_check[last_digit] == true && right_table[last_digit+len_C+1][HEAD_MATCH] == 0){
			//printf("head_matchがNOTに移動\n");
			//move = 1; //NOTに移動したと考える
		}
		ret += (left_table[last_digit][NOT]+move)*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	//printf("ret:%lld\n",ret);

	return ret;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	bool c_zero = (len_C == 1) && (C[0] == '0');

	if(c_zero){
		//printf("ZERO!!\n");
	}

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//printf("next_loc[0][0]:%d\n",next_loc[0][0]);

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	//★子孫の数のテーブルを作る★
	POW[0] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	//return 0;

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	//printf("num_A:%lld num_B:%lld minum_A:%lld\n",num_A,num_B,minus_A);

	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.5348837209302325
time_ms: 240
memory_kb: 63108
final_rank: 19

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 10001
#define SIZE 501

enum Type{
	A,
	B,
};

enum Which{
	HEAD_MATCH,
	NOT,
};

struct Node{
	int parent_id,children[10],suffix_link;
	bool finish_FLG;
};

struct Info{
    Info(int arg_node_id,int arg_ch){
        node_id = arg_node_id;
        ch = arg_ch;
    }

    int node_id,ch;
};

int next_loc[SIZE][10];
int len[2],len_C;
int root;
int memo[NUM][SIZE][2]; //memo[AorBの桁][trie-pos][head_match] = Cの数(★Cの右側のみメモる→leading_zeroはないはず)
int dp[NUM][SIZE];
ll left_table[NUM][2],right_table[NUM][2];
ll POW[NUM],num_future[NUM][2]; //num_future[残桁数][NOT],num_future[先頭桁数][HEAD_MATCH]
bool is_pre_ok[SIZE],match_check[NUM];
char buf[2][NUM],C[SIZE];
Node nodes[SIZE];


int recursive(Type type,bool c_zero,int digit,int start_digit,int trie_pos,bool leading_zero,bool head_match){

	ll ret = 0;
	int limit,next_trie_pos;

	if(digit < start_digit){ //Cを開始する左側[★★Cが成立してはいけない★★]

		if(head_match){
			limit = buf[type][digit]-'0';
		}else{
			limit = 9;
		}

		if(digit == start_digit-1){ //★次の桁でCを開始★

			//printf("start_digit:%d 次の桁で0を開始 limit:%d\n",start_digit,limit);

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len[type]))continue; //★CができてしまうならSKIP

				//printf("mausi next:%d\n",next);

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
					if(!is_pre_ok[next_trie_pos])continue; //★直前の文字になれないならSKIP
				}

				//printf("next:%d\n",next);

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
										leading_zero && next == 0,head_match && next == limit);

				ret %= MOD;
			}

		}else{

			for(int next = 0; next <= limit; next++){
				if((c_zero == true && leading_zero == false && next == 0) ||
						(c_zero == false && next_loc[trie_pos][next] == len[type]))continue; //★CができてしまうならSKIP

				if(leading_zero == true && next == 0){
					next_trie_pos = root; //★★
				}else{
					next_trie_pos = next_loc[trie_pos][next];
				}

				ret += recursive(type,c_zero,digit+1,start_digit,next_trie_pos,
														leading_zero && next == 0,head_match && next == limit);
				ret %= MOD;
			}
		}
		return (int)ret;

	}else if(digit >= start_digit && digit <= start_digit+len_C-1){ //★★Cを書く区間★★

		if(c_zero == true && leading_zero == true){ //★コーナーケース★

			if(digit == len[type]-1){ //最後の桁のみ先頭0可
				//printf("1回だけ\n");
				return 1;
			}else{
				return 0;
			}
		}

		if(head_match){ //★Cが上限を超えたらreturn 0

			if(C[digit-start_digit]-'0' > buf[type][digit]-'0'){

				//printf("ありえない\n");
				return 0;

			}else{

				ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
						false,head_match && C[digit-start_digit] == buf[type][digit]);

				return ret%MOD;
			}

		}else{

			ll ret = recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][C[digit-start_digit]-'0'],
					false,false);

			return ret%MOD;
		}

	}else{ //★C成立後★

		if(digit == len[type])return memo[digit][trie_pos][head_match] = 1; //★★★Cが成立したことによる1★★★

		if(memo[digit][trie_pos][head_match] != -1)return memo[digit][trie_pos][head_match];

		if(head_match){

			limit = buf[type][digit]-'0';

		}else{
			limit = 9;
		}

		for(int next = 0; next <= limit; next++){

			/*if(type == B && start_digit == 0 && digit == 3){
				printf("trie_pos:%d\n",trie_pos);
			}*/

			if(next_loc[trie_pos][next] == len_C){

				//★★★★★子の数分加算する★★★★★
				if(digit == len[type]-1){ //最後の桁

					ret++;

				}else{

					if(head_match == true && next  == buf[type][digit+1]){
						ret += num_future[digit+1][HEAD_MATCH];
					}else{
						ret += num_future[len[type]-(digit+1)][NOT];
					}
				}
				if(digit == start_digit+1){
					//printf("next:%d ret:%d\n",next,ret);
				}
			}
			ret += recursive(type,c_zero,digit+1,start_digit,next_loc[trie_pos][next],
					false,head_match && next == limit);

			/*if(digit == start_digit+1){
								printf("next:%d ret:%d\n",next,ret);
							}*/
			ret %= MOD;
		}

		/*if(digit == start_digit+1){
			printf("ret:%lld\n",ret);
		}*/

		return memo[digit][trie_pos][head_match] = (int)ret;
	}
}

void init(){

	for(int i = 0; i < NUM; i++){

		for(int a = 0; a < 2; a++){
			left_table[i][a] = 0;
			right_table[i][a] = 0;
		}

		for(int k = 0; k < SIZE; k++){

			memo[i][k][true] = -1;
			memo[i][k][false] = -1;

			dp[i][k] = 0;
		}
	}
}

int get_next_loc(int current_loc,int next){

	if(nodes[current_loc].children[next] != -1){

		return nodes[current_loc].children[next];

	}else{

		if(current_loc == root){
			return root;
		}

		for(current_loc = nodes[current_loc].suffix_link; current_loc != root; current_loc = nodes[current_loc].suffix_link){
			if(nodes[current_loc].children[next] != -1){
				break;
			}
		}
		if(nodes[current_loc].children[next] != -1){

			return nodes[current_loc].children[next];

		}else{

			return root;
		}
	}
}

void makeTrie(){

	int index = 1;

	nodes[root].suffix_link = -1;

	//トライ木のノードを初期化
	for(int i = 0; i <= len_C; i++){
		nodes[i].parent_id = -1;
		nodes[i].finish_FLG = false;
		for(int k = 0; k < 10; k++){
			nodes[i].children[k] = -1;
		}
	}

	int tmp_ch,tmp_loc,parent_id,tmp_index;

	//トライ木を構成する
	tmp_index = 0;
	tmp_ch = C[tmp_index]-'0';

	tmp_loc = root;
	tmp_index = 0;

	while(true){

		parent_id = tmp_loc;

		nodes[tmp_loc].children[tmp_ch] = index++; //★新しいノードへ移動する場合★
		//子ノードに移動
		tmp_loc = nodes[tmp_loc].children[tmp_ch];
		nodes[tmp_loc].parent_id = parent_id;

		tmp_index++;

		if(C[tmp_index] == '\0'){ //今回の数字が最後の文字だった場合
			nodes[tmp_loc].finish_FLG = true;
			break;
		}
		tmp_ch = C[tmp_index]-'0';
	}
}

void makeSuffixLink(){

	int node_id;
	queue<Info> MAKE_SL;

	for(int i = 0; i < 10; i++){
		if(nodes[root].children[i] != -1){
			node_id = nodes[root].children[i];
			nodes[node_id].suffix_link = root; //★root直下のsuffix_linkは必ずrootなので、queueには突っ込まない★
			for(int k = 0; k < 10; k++){
				if(nodes[node_id].children[k] != -1){
					MAKE_SL.push(Info(nodes[node_id].children[k],k)); //ノードのidと、最後の経路をpushする
				}
			}
		}
	}

	int tmp_loc,tmp_ch;

	while(!MAKE_SL.empty()){
		node_id = MAKE_SL.front().node_id; //★新たにsuffix_linkを張りたいノードのid★
		tmp_ch = MAKE_SL.front().ch;
		MAKE_SL.pop();

		for(int i = 0; i < 10; i++){
			if(nodes[node_id].children[i] != -1){
				MAKE_SL.push(Info(nodes[node_id].children[i],i));
			}
		}

		for(tmp_loc = nodes[nodes[node_id].parent_id].suffix_link; tmp_loc != root; tmp_loc = nodes[tmp_loc].suffix_link){
			if(nodes[tmp_loc].children[tmp_ch] != -1){
				break;
			}
		}

		if(tmp_loc == root){
			if(nodes[root].children[tmp_ch] != -1){
				nodes[node_id].suffix_link = nodes[root].children[tmp_ch];
			}else{
				nodes[node_id].suffix_link = root;
			}
		}else{
			nodes[node_id].suffix_link = nodes[tmp_loc].children[tmp_ch];
		}
	}
}

void calc_future(Type type){

	//num_future[先頭桁数][HEAD_MATCH]
	ll num = buf[type][len[type]-1]-'0';
	num_future[len[type]-1][HEAD_MATCH] = num+1; //+1は0の分

	for(int digit = len[type]-2; digit >= 0; digit--){
		num += POW[len[type-1]-digit]*(buf[type][digit]-'0');
		num %= MOD;
		num_future[digit][HEAD_MATCH] = num;
	}
}

int final_calc(Type type,bool c_zero){

	ll ret = 0;
	bool IS_SAME;

	//★★まず、right_tableを作る★★
	for(int start_digit = 0; start_digit+len_C <=len[type]; start_digit++){
		if(start_digit == 0){
			recursive(type,c_zero,start_digit,start_digit,0,true,true);

		}else{

			IS_SAME = true;
			for(int i = 0; i < len_C; i++){
				if(buf[type][start_digit+i] != C[i]){
					IS_SAME = false;
					break;
				}
			}
			if(IS_SAME){
				recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,true); //HEAD_MATCH
			}
			recursive(type,c_zero,start_digit+len_C,start_digit,len_C,false,false); //2桁以上であれば、NOTが0でないはず
		}
	}
	for(int digit = len_C; digit <= len[type]; digit++){
		right_table[digit][HEAD_MATCH] = max(0,memo[digit][len_C][true]); //Cが成立した時点で、まだhead_matchである場合
		right_table[digit][NOT] = max(0,memo[digit][len_C][false]);

		//printf("digit:%d head_match:%d NOT:%d\n",digit,right_table[digit][HEAD_MATCH],right_table[digit][NOT]);
	}
	//★★left_tableを作る[原則、HEAD_MATCHは常に1個とみなして(★Cが成立してしまう場合もある★)、非HEAD_MATCHを数える。また、leading_zeroは常に1通りでかつtrie-posは0]★★
	int limit,next_trie_pos,head_match_loc = root;
	bool head_match_FLG = true; //★★★★★★★head_matchしている途中でCが成立するならfalseになる★★★★
	//dp[last_digit][trie_pos] = ★★非HEAD_MATCHの場合の数★★


	//★★Cが始まる前まで★★を左側と考える
	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		if(last_digit > 0){
			match_check[last_digit-1] = head_match_FLG; //★head_matchな左側として存在し得るか★
		}

		if(last_digit == 0){ //最初の桁

			for(int next = 1; next < buf[type][0]-'0'; next++){ //0だとleading_zeroになってしまう

				next_trie_pos = next_loc[root][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos]++;
				//printf("last_digit:%d next_trie_pos:%d \n",last_digit,next_trie_pos);
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}

			continue;
		}

		//HEAD_MATCHからHEAD_MATCHでなくなる場合[★★trie-posに注意★★]
		if(head_match_FLG){

			limit = (buf[type][last_digit]-'0')-1;
			for(int next = 0; next <= limit; next++){

				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[head_match_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += 1; //HEAD_MATCHから1を配るイメージ
			}

			head_match_loc = next_loc[head_match_loc][buf[type][last_digit]-'0'];

			if(head_match_loc == len_C || is_pre_ok[head_match_loc] == false){ //★★Cが成立してしまった(しまう)ので、もう配らない★★
				//printf("digit:%d C完成\n",last_digit);
				head_match_FLG = false;
			}
		}

		//NOT
		limit = 9;
		for(int pre_loc = 0; pre_loc <= len_C-1; pre_loc++){
			for(int next = 0; next <= limit; next++){

				if(dp[last_digit-1][pre_loc] == 0)continue;
				if(c_zero == true && next == 0)continue;

				next_trie_pos = next_loc[pre_loc][next];
				if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

				dp[last_digit][next_trie_pos] += dp[last_digit-1][pre_loc];
				dp[last_digit][next_trie_pos] %= MOD;
			}
		}

		//leading_zeroからの先頭数字
		limit = 9;

		for(int next = 1; next <= limit; next++){ //先頭は0不可

			next_trie_pos = next_loc[root][next];
			if(next_trie_pos == len_C || is_pre_ok[next_trie_pos] == false)continue;

			dp[last_digit][next_trie_pos] += 1;
			dp[last_digit][next_trie_pos] %= MOD;
		}
	}
	match_check[len[type]-len_C-1] = head_match_FLG;

	bool is_over = false;

	for(int last_digit = 0; last_digit < len[type]-len_C; last_digit++){

		//printf("last_digit:%d\n",last_digit);

		if(match_check[last_digit]){

			//printf("match_check == true\n");
			left_table[last_digit][HEAD_MATCH] = 1;

		}else{
			//printf("match_check == false\n");
			left_table[last_digit][HEAD_MATCH] = 0;
		}

		if(!c_zero){
			left_table[last_digit][NOT] = 1; //★★leading_zeroの分
		}

		if(is_over == false && match_check[last_digit] == true){ //head_matchの分

			//★★★Cを続けて、buf[type]を超えてしまわないか調べる
			for(int i = 0; i < len_C; i++){
				if(C[i] < buf[type][last_digit+1+i]){
					break;
				}else if(C[i] > buf[type][last_digit+1+i]){
					is_over = true;
					break;
				}
			}

			if(!is_over){
				//printf("head_matchの分を加算\n");
				left_table[last_digit][NOT] += 1;
			}
		}

		for(int pos = 0; pos <= len_C-1; pos++){
			left_table[last_digit][NOT] += dp[last_digit][pos];
			left_table[last_digit][NOT] %= MOD;
		}

		//printf("digit:%d MATCH:%d NOT:%d\n",last_digit,left_table[last_digit][HEAD_MATCH],left_table[last_digit][NOT]);
	}

	int move;

	for(int last_digit = -1; last_digit < len[type]-len_C; last_digit++){ //★左側の右端のループ★

		if(last_digit == -1){
			ret += right_table[len_C][HEAD_MATCH];
			ret += right_table[len_C][NOT];
			ret %= MOD;
			//printf("先頭から:%lld\n",ret);
			continue;
		}

		move = 0;
		//ret += right_table[last_digit+len_C+1][HEAD_MATCH];

		//★★パターンを書いたことにより、HEAD_MATCHがなくなった場合
		/*if(match_check[last_digit] == true){
			printf("digit:%d matchがtrue\n",last_digit);
			printf("right:%d\n",right_table[last_digit+len_C+1][HEAD_MATCH]);
		}*/

		if(match_check[last_digit] == true && right_table[last_digit+len_C+1][HEAD_MATCH] == 0){
			//printf("head_matchがNOTに移動\n");
			//move = 1; //NOTに移動したと考える
		}
		ret += (left_table[last_digit][NOT]+move)*right_table[last_digit+len_C+1][NOT];
		ret %= MOD;
	}
	if(c_zero)ret++;

	//printf("ret:%lld\n",ret);

	return ret;
}

int main(){

	scanf("%s %s %s",buf[A],buf[B],C);

	int length;

	for(length = 0; buf[A][length] != '\0'; length++);
	len[A] = length;
	for(length = 0; buf[B][length] != '\0'; length++);
	len[B] = length;
	for(length = 0; C[length] != '\0'; length++);
	len_C = length;

	bool c_zero = (len_C == 1) && (C[0] == '0');

	if(c_zero){
		//printf("ZERO!!\n");
	}

	//Cのトライ木構築&&SuffixLinkを張る
	root = 0;
	makeTrie();
	makeSuffixLink();

	//next_locの計算→[trie-pos]ごとに、nextの10個を探索
	for(int current_loc = 0; current_loc <= len_C; current_loc++){
		for(int next = 0; next <= 9; next++){

			next_loc[current_loc][next] = get_next_loc(current_loc,next);
		}
	}

	//printf("next_loc[0][0]:%d\n",next_loc[0][0]);

	//直前の文字になれるか全探索
	bool FLG;
	int tmp_loc;

	for(int start_loc = 0; start_loc <= len_C-1; start_loc++){

		FLG = true;
		tmp_loc = start_loc;

		for(int i = 0; i < len_C; i++){

			tmp_loc = next_loc[tmp_loc][C[i]-'0'];

			if(tmp_loc == len_C && i <= len_C-2){ //★途中でCが成立したら不可
				FLG = false;
				break;
			}
		}
		is_pre_ok[start_loc] = FLG;
	}

	//Aに含まれているCの個数を探索
	ll minus_A = 0;

	for(int start_digit = 0; start_digit+len_C <= len[A]; start_digit++){

		FLG = true;

		for(int i = 0; i < len_C; i++){

			if(buf[A][start_digit+i] != C[i]){

				FLG = false;
				break;
			}
		}
		if(FLG)minus_A++;
	}

	ll num_A,num_B;

	//★子孫の数のテーブルを作る★
	POW[0] = 1;

	for(int i = 1; i < NUM; i++){

		POW[i] = POW[i-1]*10;
		POW[i] %= MOD;

		num_future[i][NOT] = POW[i];
	}

	init();
	calc_future(A);
	num_A = final_calc(A,c_zero);

	//return 0;

	init();
	calc_future(B);
	num_B = final_calc(B,c_zero);

	//printf("num_A:%lld num_B:%lld minum_A:%lld\n",num_A,num_B,minus_A);

	ll ans = num_B-(num_A-minus_A);
	ans %= MOD;
	if(ans < 0)ans += MOD;

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.37209302325581395
time_ms: 20
memory_kb: 62492
final_rank: 20