model your problem as 2 combined lattices in 2 dimensions, in particular, as pairs (i,j) connected with oriented edges ((i0,j0),(i1,j1)) , where i1 = i0 + 1, |j1 - j0| = 1 i1 = i0 + 1, |j1 - j0| = 1 , modified as follows:
- discarding all pairs (i, j) with
j > 9 and its falling edges - discarding all pairs (i, j) with
i > m-1 and its falling edges - falling edge
((0,0), (1,1))
this design leads to a structure, as in this diagram:
:
the requested numbers are displayed on the path in the lattice, starting with one of the green elements ( (0,j), j=1..min(n-1,9) ), which contain at least one pink and one red element ( (i,0), i=1..m-1 , (i,n-1), i=0..m-1 ). to see this, identify the digit i -th j given number with the dot (i,j) . including pink and red elements ("extreme numbers") ensure that all available numbers are represented in a number.
Analysis
for convenience, let q1, q2 denote the position -1.
let q1 be the position of the first digit of the number, which is either 0 or min(n-1,9) . let q2 be the position of the number, first 0 , if the digit at position q1 is min(n-1,9) and vv.
case 1 : the first extreme digit is 0
the number of valid prefixes that do not contain 0 can be expressed as sum_{k=1..min(n-1,9)} (paths_to_0(k,1,q1) , and the function paths_to_0 recursively defined as
paths_to_0(0,q1-1,q1) = 0; paths_to_0(1,q1-1,q1) = 1; paths_to_0(digit,i,q1) = 0; if q1-i < digit; paths_to_0(x,_,_) = 0; if x >= min(n-1,9) // x=min(n-1,9) mustn't occur before position q2, // x > min(n-1,9) not at all paths_to_0(x,_,_) = 0; if x <= 0; // x=0 mustn't occur before position q1, // x < 0 not at all and else paths_to_0(digit,i,q1) = paths_to_0(digit+1,i+1,q1) + paths_to_0(digit-1,i+1,q1);
similarly we have
paths_to_max(min(n-1,9),q2-1,q2) = 0; paths_to_max(min(n-2,8),q2-1,q2) = 1; paths_to_max(digit,i,q2) = 0 if q2-i < n-1; paths_to_max(x,_,_) = 0; if x >= min(n-1,9) // x=min(n-1,9) mustn't occur before // position q2, // x > min(n-1,9) not at all paths_to_max(x,_,_) = 0; if x < 0; and else paths_to_max(digit,q1,q2) = paths_max(digit+1,q1+1,q2) + paths_to_max(digit-1,q1+1,q2);
and finally
paths_suffix(digit,length-1,length) = 2; if digit > 0 and digit < min(n-1,9) paths_suffix(digit,length-1,length) = 1; if digit = 0 or digit = min(n-1,9) paths_suffix(digit,k,length) = 0; if length > m-1 or length < q2 or k > length paths_suffix(digit,k,0) = 1; // the empty path and else paths_suffix(digit,k,length) = paths_suffix(digit+1,k+1,length) + paths_suffix(digit-1,k+1,length);
... for total cost
number_count_case_1(n, m) = sum_{first=1..min(n-1,9), q1=1..m-1-(n-1), q2=q1..m-1, l_suffix=0..m-1-q2} ( paths_to_0(first,1,q1) + paths_to_max(0,q1,q2) + paths_suffix(min(n-1,9),q2,l_suffix+q2) )
case 2 : the first extreme digit is min(n-1,9)
case 2.1 : the initial digit is not min(n-1,9) this is symmetric to case 1 with the replacement of all digits d by min(n,10) - d . since the lattice structure is symmetrical, this means number_count_case_2_1 = number_count_case_1 .
Case 2.2 : The initial digit is min(n-1,9) note that q1 is 1 , and the second digit should be min(n-2,8) . Thus,
number_count_case_2_2 (n, m) = sum_{q2=1..m-2, l_suffix=0..m-2-q2} ( paths_to_max(1,1,q2) + paths_suffix(min(n-1,9),q2,l_suffix+q2) )
so the overall result will be
number_count ( n, m ) = 2 * number_count_case_1 (n, m) + number_count_case_2_2 (n, m);
the code
I donโt know if there is a closed expression for number_count , but the following Perl code will calculate it (the code is just a confirmation of the concept, since it does not use storage methods to avoid recounting the results already obtained):
use strict; use warnings; my ($n, $m) = ( 5, 7 ); # for example $n = ($n > 10) ? 10 : $n; # cutoff sub min sub paths_to_0 ($$$) { my ( $d , $at , $until ) = @_; # if (($d == 0) && ($at == $until - 1)) { return 0; } if (($d == 1) && ($at == $until - 1)) { return 1; } if ($until - $at < $d) { return 0; } if (($d <= 0) || ($d >= $n))) { return 0; } return paths_to_0($d+1, $at+1, $until) + paths_to_0($d-1, $at+1, $until); } # paths_to_0 sub paths_to_max ($$$) { my ( $d , $at , $until ) = @_; # if (($d == $n-1) && ($at == $until - 1)) { return 0; } if (($d == $n-2) && ($at == $until - 1)) { return 1; } if ($until - $at < $n-1) { return 0; } if (($d < 0) || ($d >= $n-1)) { return 0; } return paths_to_max($d+1, $at+1, $until) + paths_to_max($d-1, $at+1, $until); } # paths_to_max sub paths_suffix ($$$) { my ( $d , $at , $until ) = @_; # if (($d < $n-1) && ($d > 0) && ($at == $until - 1)) { return 2; } if ((($d == $n-1) && ($d == 0)) && ($at == $until - 1)) { return 1; } if (($until > $m-1) || ($at > $until)) { return 0; } if ($until == 0) { return 1; } return paths_suffix($d+1, $at+1, $until) + paths_suffix($d-1, $at+1, $until); } # paths_suffix # # main # number_count = sum_{first=1..min(n-1,9), q1=1..m-1-(n-1), q2=q1..m-1, l_suffix=0..m-1-q2} ( paths_to_0(first,1,q1) + paths_to_max(0,q1,q2) + paths_suffix(min(n-1,9),q2,l_suffix+q2) ) my ($number_count, $number_count_2_2) = (0, 0); my ($first, $q1, i, $l_suffix); for ($first = 1; $first <= $n-1; $first++) { for ($q1 = 1; $q1 <= $m-1 - ($n-1); $q1++) { for ($q2 = $q1; $q2 <= $m-1; $q2++) { for ($l_suffix = 0; $l_suffix <= $m-1 - $q2; $l_suffix++) { $number_count = $number_count + paths_to_0($first,1,$q1) + paths_to_max(0,$q1,$q2) + paths_suffix($n-1,$q2,$l_suffix+$q2) ; } } } } # # case 2.2 # for ($q2 = 1; $q2 <= $m-2; $q2++) { for ($l_suffix = 0; $l_suffix <= $m-2 - $q2; $l_suffix++) { $number_count_2_2 = $number_count_2_2 + paths_to_max(1,1,$q2) + paths_suffix($n-1,$q2,$l_suffix+$q2) ; } } $number_count = 2 * $number_count + number_count_2_2;