<p>You are given two numeric strings <code>num1</code> and <code>num2</code> and two integers <code>max_sum</code> and <code>min_sum</code>. We denote an integer <code>x</code> to be <em>good</em> if:</p>

<ul>
	<li><code>num1 &lt;= x &lt;= num2</code></li>
	<li><code>min_sum &lt;= digit_sum(x) &lt;= max_sum</code>.</li>
</ul>

<p>Return <em>the number of good integers</em>. Since the answer may be large, return it modulo <code>10<sup>9</sup> + 7</code>.</p>

<p>Note that <code>digit_sum(x)</code> denotes the sum of the digits of <code>x</code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> num1 = &quot;1&quot;, num2 = &quot;12&quot;, <code>min_sum</code> = 1, max_sum = 8
<strong>Output:</strong> 11
<strong>Explanation:</strong> There are 11 integers whose sum of digits lies between 1 and 8 are 1,2,3,4,5,6,7,8,10,11, and 12. Thus, we return 11.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> num1 = &quot;1&quot;, num2 = &quot;5&quot;, <code>min_sum</code> = 1, max_sum = 5
<strong>Output:</strong> 5
<strong>Explanation:</strong> The 5 integers whose sum of digits lies between 1 and 5 are 1,2,3,4, and 5. Thus, we return 5.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= num1 &lt;= num2 &lt;= 10<sup>22</sup></code></li>
	<li><code>1 &lt;= min_sum &lt;= max_sum &lt;= 400</code></li>
</ul>

class Solution:
    def count(self, num1: str, num2: str, min_sum: int, max_sum: int) -> int:
        MOD = 10**9 + 7

        from functools import lru_cache

        def count_numbers(num):
            L = len(num)

            @lru_cache(maxsize=None)
            def dp(pos, tight, sum):
                if sum > max_sum:
                    return 0
                if pos == L:
                    return 1 if min_sum <= sum <= max_sum else 0
                res = 0
                up = int(num[pos]) if tight else 9
                for d in range(0, up + 1):
                    tight_next = tight and (d == up)
                    res += dp(pos + 1, tight_next, sum + d)
                return res % MOD

            return dp(0, True, 0)

        def count_numbers_min(num):
            L = len(num)

            @lru_cache(maxsize=None)
            def dp(pos, tight, sum, non_zero):
                if sum > max_sum:
                    return 0
                if pos == L:
                    return 1 if min_sum <= sum <= max_sum and non_zero else 0
                res = 0
                low = int(num[pos]) if tight else 0
                for d in range(low, 10):
                    tight_next = tight and (d == low)
                    if non_zero or d != 0:
                        res += dp(pos + 1, tight_next, sum + d, non_zero or d != 0)
                return res % MOD

            return dp(0, True, 0, False)

        def subtract_one(num_str):
            num_list = list(num_str)
            idx = len(num_list) - 1
            while idx >= 0:
                if num_list[idx] != '0':
                    num_list[idx] = str(int(num_list[idx]) - 1)
                    break
                else:
                    num_list[idx] = '9'
                    idx -= 1
            if idx == -1:
                num_list = ['0']
            return ''.join(num_list).lstrip('0') or '0'

        count_num2 = count_numbers(num2)
        num1_minus_one = subtract_one(num1)
        count_num1 = count_numbers(num1_minus_one)
        ans = (count_num2 - count_num1) % MOD

        return ans

18300