Count integers between large A and B having counter S

I am trying to count integers between a range A and B having the digit sum S (assuming S = 60).

A and B range from 1 to 10 ^ 18.

let X be a number and Upto Y, we must count the integers.

X = x1 x2 ... xn - 1 xn and Y = y1 y2 ... yn - 1 yn, where xi and yi are decimal numbers of X and Y.

leftmost_lo as the smallest self with xi <yr. We define leftmost_lo as n + 1 if I am not. Similarly, we define leftmost_hi as the smallest self with xi> yi or n + 1 otherwise.

The count function returns the number f (Y) of the integers X with the property X ≤ Y and X has the digit sum 60.

Let n be the number of Y-digits and y [i] the i-th decimal digit Y in accordance with the above definition. The following recursive algorithm solves the problem:

    count(i, sum_so_far, leftmost_lo, leftmost_hi):
       if i == n + 1:
       # base case of the recursion, we have recursed beyond the last digit
       # now we check whether the number X we built is a valid solution
        if sum_so_far == 60 and leftmost_lo <= leftmost_hi:
          return 1
        else: 
          return 0
     result = 0
     # we need to decide which digit to use for x[i]
     for d := 0 to 9
        leftmost_lo' = leftmost_lo
        leftmost_hi' = leftmost_hi
        if d < y[i] and i < leftmost_lo': leftmost_lo' = i
        if d > y[i] and i < leftmost_hi': leftmost_hi' = i
       result += count(i + 1, sum_so_far + d, leftmost_lo', leftmost_hi')
    return result






Compute the number f(Y) of integers X with the property X ≤ Y and X has the digit sum 60

f (Y) = count (1, 0, n + 1, n + 1), .

O (n ^ 4) .

. . A B ?

, .

O (n) .

- .

+4
3

, ! , , , . , , , .


" 18 ", " 1 10 ^ 18". ( 18 18- .)

, , , .

dig 1 9, 0, . ( 18 - sum(dig). :

recurse(dig[], pos) {
    if (digitsum(dig) > 60) return;

    if (digitsum(dig) == 60) {
        count += poss(dig)
    } else {
        if (pos < 9) recurse(dig, pos + 1);
        if (sum(dig) < 18) {
            dig[pos]++;
            recurse(dig, pos);
            dig[pos]--;
        }  
    }
}

, 60. 60 , , :

poss(dig) = 18! / prod(dig[i]!)

prod(dig[i]!) . (, , 0! == 1.)

, . , 60 50 5 000 000 000, .


, , A B. 0 10 ^ n, n- , .

- , . , 5x 9 3x 5, 60. , 18 . 590,050,005,090,900,099 - , . 18 - (5 + 3) = 10 ,

N(5x9, 3x5) = 18! / (5! * 3! * 10!)

.

. , dig:

     ^ count
     |
2x   ...  ...  ...  ...  ...  ...  ...  ...  ... 

1x   ...  ...  ...  ...  ...  ...  ...  ...  ...  

0x   ...  ...  ...  ...  ...  ...  ...  ...  ...

     ---------------------------------------------> pos
      1    2    3    4    5    6    7    8    9

dig == [0, 0, 0, 0, 3, 0, 0, 0, 5]

, . pos. , , . , S, pos 9. , S, , .

, : .

18- , 60 .

, . , 18! 64- , 20! . (, N! / prod(dig[i]!).)

. , . bare-bones:

ds_count(i, sum)
{
    if (sum > 60) return 0;

    if (i == 18) {
        if (sum == 60) return 1;
        return 0;
    }

    result = 0;
    for (d = 0; d < 10; d++) {
        result += ds_count(i + 1, sum + d);
    }

    return result;
}

18- . , 60, . , .

. , , . , ds_count(2, 5) 05..., 14..., 23..., 32..., 41... 50.... ( Settlers of Catan, .)

, 5 16 . :

ds_count(i, sum)
{
    if (sum > 60) return 0;

    if (i == 18) {
        if (sum == 60) return 1;
        return 0;
    }

    if (defined(memo[i, sum])) return memo[i, sum];

    result = 0;
    for (d = 0; d < 10; d++) {
        result += ds_count(i + 1, sum + d);
    }

    memo[i, sum] = result;
    return result;
}

, . , .

, memoizing. ( memoizing , .) zig-zag - . , , memoising .

0

-, , F, ints <= A sum S, int A B S F (B) -F (-1).

:

  • n (A) , 9 , A). , n (123) = 999.
  • A [0] A
  • A [1:] A .

, , , A, ( A 9s).

F(S, A) = 1 if S = 0
F(S, A) = 0 if S < 0 or A = 0
otherwise F(S, A) =
    F(S-A[0], A[1:])
    + F(S-0, n(A[1:])) + F(S-1, n(A[1:])) + ... + F(S-A[0]-1, n(A[1:]))

( , ):

def count1(S, digits, nines, k, cache):
    if S <= 0 or k == len(digits): return S==0
    key = (S, nines, k)
    if key not in cache:
        dk = 9 if nines else digits[k]
        cache[key] = sum(count1(S-i, digits, nines or i<dk, k+1, cache)
                         for i in xrange(dk+1))
    return cache[key]

def count(S, A):
    return count1(S, map(int, str(A)), False, 0, {})

def count_between(S, A, B):
    return count(S, B) - count(S, A-1)

print count_between(88, 1, 10**10)

S * 2 * len (str (A)), , : O (S * log_10 (A)).

+2

A = 1 B = 10 ^ 18, S, 19 10. (18 - number_of_parts) .

A B , :)

1 B , :

, B b1 b2... bn - 1 bn. b1 ( , n , 10) S - (b1 - 1) (n - 1 - number_of_parts) . b1 = 0 ( ). b2, S b1. , .

A B f (A) f (B).

JavaScript:

function choose(n,k){
  if (k == 0 || n == k){
    return 1;
  }
  var product = n;
  for (var i=2; i<=k; i++){
    product *= (n + 1 - i) / i
  }
  return product;
}

function digits(n){
  var ds = [];
  while (n){
    ds.push(n % 10);
    n = Math.floor(n/10);
  }
  return ds.reverse()
}

function ps(n,maxParts){
  if (maxParts <= 0){
    return 0;
  }
  var result = 0;
  for (var i=9; i>=Math.floor(n/maxParts); i--){
    var r = [0,0,0,0,0,0,0,0,0,0,1]; // 11th place is number of parts
    r[i]++;
    result += _ps(n-i,r,i,1,maxParts);
  }
  return result;
}

function _ps(n,r,i,c,maxParts){
  if (n==0){
    return numPs(r,maxParts);
  } else if (c==maxParts || n<0){
    return 0;
  } else{
    var result = 0;
    for (var j=i; j>0; j--){
      var r0 = r.slice();
      r0[j]++;
      r0[10]++;
      result += _ps(n-j,r0,j,c+1,maxParts);
    }
    return result;
  }
}

function numPs(partition,n){
  var l = choose(n,n - partition[10]);
  n = partition[10];
  for (var i=0; i<10;i++){
    if (partition[i] != 0){
      l *= choose(n,partition[i]);
      n -= partition[i];
    }
  }
  return l;
}

function f(n,s){
  var ds = digits(n),
      n = ds.length,
      answer = 0;
  for (var i=0; i<n - 1; i++){
    if (ds[i] != 0){
      var d = ds[i] - 1;
      while (d >= 0){
        answer += ps(s - d,n - i - 1);
        d--;
      }
      s -= ds[i];
    }
  }
  if (s <= ds[n - 1]){
    answer++;
  }

  return answer;
}

:

console.log(f(1,1));
1

console.log(f(1000,3));
10

console.log(f(1001,3));
10

console.log(f(1002,3));
11

console.log(f(1003,3));
11

console.log(f(1010,3));
11
+1

All Articles