Open In App

Count N digits numbers with sum divisible by K

Last Updated : 15 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two integers N and K, the task is to count all N digits numbers whose sum of digits is divisible by K.

Examples:

 Input: N = 2, K = 7
Output: 12
Explanation: 2 digits numbers with sum divisible by 7 are: {16, 25, 34, 43, 52, 59, 61, 68, 70, 77, 86, 95}.
Therefore, the required output is 12.

Input: N = 1, K = 2
Output: 4

Naive Approach: The simplest approach is to traverse all the numbers from the range [10(N – 1), 10N – 1] and check if the sum of all the digits of a number that lies within the range is divisible by K or not. For every number for which the condition is found to be true, increase count. Finally, print the count.

Time Complexity: O(10N – 10N – 1 – 1)
Auxiliary Space: O(1)

Efficient Approach: The idea is to use Digit DP technique to optimize the above approach. Below is the recurrence relation:

CountNum(N, sum, st) = \sum^{9}_{i=0} countNum(N - 1, (sum + i)\mod K, st)
 

sum: represents sum of digits 
st: check if a number contains any leading 0. 
 


 

Follow the steps below to solve the problem:  

  1. Initialize a 3D array dp[N][K][st] to compute and store the values of all subproblems of the above recurrence relation.
  2. Finally, return the value of dp[N][sum%K][st].

C++

// C++ Program to implement
// the above approach
 
#include <bits/stdc++.h>
using namespace std;
#define M 1000
 
// Function to count the N digit numbers
// whose sum is divisible by K
int countNum(int N, int sum, int K,
             bool st, int dp[M][M][2])
{
    // Base case
    if (N == 0 and sum == 0) {
        return 1;
    }
    if (N < 0) {
        return 0;
    }
 
    // If already computed
    // subproblem occurred
    if (dp[N][sum][st] != -1) {
        return dp[N][sum][st];
    }
 
    // Store the count of N digit numbers
    // whose sum is divisible by K
    int res = 0;
 
    // Check if the number does not contain
    // any leading 0.
    int start = st == 1 ? 0 : 1;
 
    // Recurrence relation
    for (int i = start; i <= 9; i++) {
        res += countNum(N - 1, (sum + i) % K,
                        K, (st | i > 0), dp);
    }
 
    return dp[N][sum][st] = res;
}
 
// Driver Code
int main()
{
    int N = 2, K = 7;
 
    // Stores the values of
    // overlapping subproblems
    int dp[M][M][2];
 
    memset(dp, -1, sizeof(dp));
 
    cout << countNum(N, 0, K, 0, dp);
}

                    

Java

// Java program to implement
// the above approach
import java.util.*;
import java.lang.*;
 
class GFG {
 
    static final int M = 1000;
 
    // Function to count the N digit numbers
    // whose sum is divisible by K
    static int countNum(int N, int sum, int K,
                        int st, int dp[][][])
    {
 
        // Base case
        if (N == 0 && sum == 0) {
            return 1;
        }
        if (N < 0) {
            return 0;
        }
 
        // If already computed
        // subproblem occurred
        if (dp[N][sum][st] != -1) {
            return dp[N][sum][st];
        }
 
        // Store the count of N digit numbers
        // whose sum is divisible by K
        int res = 0;
 
        // Check if the number does not contain
        // any leading 0.
        int start = st == 1 ? 0 : 1;
 
        // Recurrence relation
        for (int i = start; i <= 9; i++) {
            res += countNum(N - 1, (sum + i) % K,
                            K, ((st | i) > 0) ? 1 : 0, dp);
        }
        return dp[N][sum][st] = res;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int N = 2, K = 7;
 
        // Stores the values of
        // overlapping subproblems
        int[][][] dp = new int[M][M][2];
 
        for (int[][] i : dp)
            for (int[] j : i)
                Arrays.fill(j, -1);
 
        System.out.print(countNum(N, 0, K, 0, dp));
    }
}
 
// This code is contributed by offbeat

                    

Python3

# Python3 program to implement
# the above approach
 
# Function to count the N digit
# numbers whose sum is divisible by K
def countNum(N, sum, K, st, dp):
     
    # Base case
    if (N == 0 and sum == 0):
        return 1
 
    if (N < 0):
        return 0
 
    # If already computed
    # subproblem occurred
    if (dp[N][sum][st] != -1):
        return dp[N][sum][st]
 
    # Store the count of N digit
    # numbers whose sum is divisible by K
    res = 0
    start = 1
     
    # Check if the number does not contain
    # any leading 0.
    if (st == 1):
        start = 0
    else:
        start = 1
 
    # Recurrence relation
    for i in range(start, 10):
        min = 0
         
        if ((st | i) > 0):
            min = 1
        else:
            min = 0
             
        res += countNum(N - 1, (sum + i) % K,
                        K, min, dp)
        dp[N][sum][st] = res
         
    return dp[N][sum][st]
 
# Driver code
if __name__ == '__main__':
     
    N = 2
    K = 7
    M = 100
     
    # Stores the values of
    # overlapping subproblems
    dp = [[[-1 for i in range(2)]
               for j in range(M)]
               for j in range(M)]
 
    print(countNum(N, 0, K, 0, dp))
 
# This code is contributed by shikhasingrajput

                    

C#

// C# program to implement
// the above approach
using System;
 
class GFG{
     
static int M = 1000;
 
// Function to count the N digit numbers
// whose sum is divisible by K
static int countNum(int N, int sum, int K,
                    int st, int[,, ] dp)
{
     
    // Base case
    if (N == 0 && sum == 0)
    {
        return 1;
    }
    if (N < 0)
    {
        return 0;
    }
 
    // If already computed
    // subproblem occurred
    if (dp[N, sum, st] != -1)
    {
        return dp[N, sum, st];
    }
 
    // Store the count of N digit numbers
    // whose sum is divisible by K
    int res = 0;
 
    // Check if the number does not contain
    // any leading 0.
    int start = (st == 1 ? 0 : 1);
     
    // Recurrence relation
    for(int i = start; i <= 9; i++)
    {
        res += countNum(N - 1, (sum + i) % K,
                        K, ((st | i) > 0) ? 1 : 0, dp);
    }
    return dp[N, sum, st] = res;
}
 
// Driver code
static public void Main()
{
    int N = 2, K = 7;
     
    // Stores the values of
    // overlapping subproblems
    int[,, ] dp = new int[M, M, 2];
 
    for(int i = 0; i < M; i++)
        for(int j = 0; j < M; j++)
            for(int k = 0; k < 2; k++)
                dp[i, j, k] = -1;
 
    Console.WriteLine(countNum(N, 0, K, 0, dp));
}
}
 
// This code is contributed by offbeat

                    

Javascript

<script>
 
// JavaScript Program to implement
// the above approach
 
var M = 1000;
 
// Function to count the N digit numbers
// whose sum is divisible by K
function countNum(N, sum, K, st, dp)
{
    // Base case
    if (N == 0 && sum == 0) {
        return 1;
    }
    if (N < 0) {
        return 0;
    }
 
    // If already computed
    // subproblem occurred
    if (dp[N][sum][st] != -1) {
        return dp[N][sum][st];
    }
 
    // Store the count of N digit numbers
    // whose sum is divisible by K
    var res = 0;
 
    // Check if the number does not contain
    // any leading 0.
    var start = st == 1 ? 0 : 1;
 
    // Recurrence relation
    for (var i = start; i <= 9; i++) {
        res += countNum(N - 1, (sum + i) % K,
                        K, (st | i > 0), dp);
    }
 
    return dp[N][sum][st] = res;
}
 
// Driver Code
 
var N = 2, K = 7;
 
// Stores the values of
// overlapping subproblems
var dp = Array.from(Array(M), ()=>Array(M));
for(var i =0; i<M; i++)
        for(var j =0; j<M; j++)
            dp[i][j] = new Array(2).fill(-1);
document.write( countNum(N, 0, K, 0, dp));
 
 
</script>

                    

Output
12








Time Complexity:O(10*N*K)
Auxiliary Space: O(N*K)

Efficient approach : Using DP Tabulation method ( Iterative approach )

The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.

Steps to solve this problem :

  • Create a table 3D DP table to store the solution of the subproblems which is of length N * K * 2 (true , false) .
  • Initialize the table with base cases
  • Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
  • Return the final solution stored in dp[N][sum][1] + dp[N][sum][0] .

Implementation :

C++

// C++ program for above approach
 
#include <bits/stdc++.h>
using namespace std;
 
// Function to count the N digit numbers
// whose sum is divisible by K
int countNum(int N, int sum, int K) {
   
      // initialize DP to Store computations of subproblems
    int dp[N + 1][K][2];
    memset(dp, 0, sizeof(dp));  // fill DP with 0
 
    // Base case
    dp[0][0][0] = 1;
     
      // Iterate over subproblems and get the solution
      // of current problem with the help of recursion
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j < K; j++) {
            for (int k = (i == 1); k <= 9; k++) { // skip leading zeroes
                int rem = (j - k % K + K) % K;
                   
                  // get current value from previous computation
               
                dp[i][j][1] += dp[i - 1][rem][1];
                if (k > 0)
                    dp[i][j][1] += dp[i - 1][rem][0];
                else
                    dp[i][j][0] += dp[i - 1][rem][0];
            }
        }
    }
     
      // return answer
    return dp[N][sum][1] + dp[N][sum][0];
}
 
// Drivre Code
 
int main() {
    int N = 2, K = 7;
   
      // function call
    cout << countNum(N, 0, K) << endl;
    return 0;
}
 
// this code is contributed by bhardwajji

                    

Java

import java.util.*;
 
public class Main {
 
  // Function to count the N digit numbers
  // whose sum is divisible by K
  public static int countNum(int N, int sum, int K) {
 
    // initialize DP to Store computations of subproblems
    int[][][] dp = new int[N + 1][K][2];
    for (int[][] row : dp)
      for (int[] innerRow : row)
        Arrays.fill(innerRow, 0); // fill DP with 0
 
    // Base case
    dp[0][0][0] = 1;
 
    // Iterate over subproblems and get the solution
    // of current problem with the help of recursion
    for (int i = 1; i <= N; i++) {
      for (int j = 0; j < K; j++) {
        for (int k = (i == 1 ? 1 : 0); k <= 9; k++) { // skip leading zeroes
          int rem = (j - k % K + K) % K;
 
          // get current value from previous computation
 
          dp[i][j][1] += dp[i - 1][rem][1];
          if (k > 0)
            dp[i][j][1] += dp[i - 1][rem][0];
          else
            dp[i][j][0] += dp[i - 1][rem][0];
        }
      }
    }
 
    // return answer
    return dp[N][sum][1] + dp[N][sum][0];
  }
 
  // Driver Code
  public static void main(String[] args) {
    int N = 2, K = 7;
 
    // function call
    System.out.println(countNum(N, 0, K));
  }
}

                    

Python3

def count_num(n, sum_, k):
    # initialize DP to Store computations of subproblems
    dp = [[[0] * 2 for _ in range(k)] for _ in range(n + 1)]
 
    # Base case
    dp[0][0][0] = 1
 
    # Iterate over subproblems and get the solution
    # of current problem with the help of recursion
    for i in range(1, n + 1):
        for j in range(k):
            for l in range(10):
                if i == 1 and l == 0:
                    continue
                rem = (j - l % k + k) % k
 
                # get current value from previous computation
                dp[i][j][1] += dp[i - 1][rem][1]
                if l > 0:
                    dp[i][j][1] += dp[i - 1][rem][0]
                else:
                    dp[i][j][0] += dp[i - 1][rem][0]
 
    # return answer
    return dp[n][sum_][1] + dp[n][sum_][0]
 
 
# Drivre Code
if __name__ == '__main__':
    n = 2
    k = 7
 
    # function call
    print(count_num(n, 0, k))

                    

C#

using System;
 
class GFG {
   
    // Function to count the N digit numbers
    // whose sum is divisible by K
    static int countNum(int N, int sum, int K)
    {
        // initialize DP to Store computations of
        // subproblems
        int[, , ] dp = new int[N + 1, K, 2];
        Array.Clear(dp, 0, dp.Length); // fill DP with 0
 
        // Base case
        dp[0, 0, 0] = 1;
 
        // Iterate over subproblems and get the solution
        // of current problem with the help of recursion
        for (int i = 1; i <= N; i++) {
            for (int j = 0; j < K; j++) {
                for (int k = (i == 1 ? 1 : 0); k <= 9;
                     k++) // skip leading zeroes
                {
                    int rem = (j - k % K + K) % K;
 
                    // get current value from previous
                    // computation
                    dp[i, j, 1] += dp[i - 1, rem, 1];
                    if (k > 0)
                        dp[i, j, 1] += dp[i - 1, rem, 0];
                    else
                        dp[i, j, 0] += dp[i - 1, rem, 0];
                }
            }
        }
 
        // return answer
        return dp[N, sum, 1] + dp[N, sum, 0];
    }
 
    // Drivre Code
    static void Main()
    {
        int N = 2;
        int K = 7;
        Console.WriteLine(countNum(N, 0, K));
    }
}

                    

Javascript

function countNum(N, sum, K) {
 
// initialize DP to Store computations of subproblems
let dp = new Array(N + 1);
for (let i = 0; i <= N; i++) {
dp[i] = new Array(K);
for (let j = 0; j < K; j++) {
dp[i][j] = new Array(2).fill(0);
}
}
 
// Base case
dp[0][0][0] = 1;
 
// Iterate over subproblems and get the solution
// of current problem with the help of recursion
for (let i = 1; i <= N; i++) {
for (let j = 0; j < K; j++) {
for (let k = (i == 1 ? 1 : 0); k <= 9; k++) { // skip leading zeroes
let rem = (j - k % K + K) % K;
    // get current value from previous computation
    dp[i][j][1] += dp[i - 1][rem][1];
    if (k > 0)
      dp[i][j][1] += dp[i - 1][rem][0];
    else
      dp[i][j][0] += dp[i - 1][rem][0];
  }
}
}
 
// return answer
return dp[N][sum][1] + dp[N][sum][0];
}
 
// Driver Code
let N = 2, K = 7;
console.log(countNum(N, 0, K));

                    

Output
12









Time Complexity: O(10*N*K)
Auxiliary Space: O(N*K)

Optmized approach: Using DP Tabulation method (Iterative approach) with Space Optimization

The approach to solve this problem remains the same, but we will utilize DP tabulation (bottom-up) method with a space-efficient optimization using “prev” and “curr” arrays.

Steps to solve this problem using space optimization:

  1. Create two 2D arrays: “prev” and “curr”, each of length [K][2].
  2. Initialize the “prev” array with base cases.
  3. Iterate over the subproblems to compute the current problem’s value using the previous computations stored in the “prev” array.
  4. Update the “curr” array with the calculated values for the current iteration.
  5. Copy the values of the “curr” array to the “prev” array, and reset the “curr” array to all zeros for the next iteration.
  6. Finally, return the final solution stored in prev[sum][1] + prev[sum][0].

Below is the implementation of the above approach:

C++

// C++ implementation of space optmized approach
#include <bits/stdc++.h>
using namespace std;
 
int countNum(int N, int sum, int K)
{
    int prev[K][2] = { 0 };
    int curr[K][2] = { 0 };
 
    // Base case
    prev[0][0] = 1;
 
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j < K; j++) {
            for (int k = (i == 1); k <= 9;
                 k++) { // skip leading zeroes
                int rem = (j - k % K + K) % K;
 
                curr[j][1] += prev[rem][1];
                if (k > 0)
                    curr[j][1] += prev[rem][0];
                else
                    curr[j][0] += prev[rem][0];
            }
        }
        // Copy curr to prev for the next iteration
        for (int j = 0; j < K; j++) {
            prev[j][0] = curr[j][0];
            prev[j][1] = curr[j][1];
            curr[j][0] = 0;
            curr[j][1] = 0;
        }
    }
 
    return prev[sum][1] + prev[sum][0];
}
 
int main()
{
    int N = 2, K = 7;
 
    cout << countNum(N, 0, K) << endl;
    return 0;
}
 
// This code is contributed by Tapesh(tapeshdua420)

                    

Java

// Java implementation of space optimized approach
import java.util.*;
 
class Main {
    public static int countNum(int N, int sum, int K) {
        int[][] prev = new int[K][2];
        int[][] curr = new int[K][2];
 
        // Base case
        prev[0][0] = 1;
 
        for (int i = 1; i <= N; i++) {
            for (int j = 0; j < K; j++) {
                for (int k = (i == 1) ? 1 : 0; k <= 9; k++) { // skip leading zeroes
                    int rem = (j - k % K + K) % K;
 
                    curr[j][1] += prev[rem][1];
                    if (k > 0)
                        curr[j][1] += prev[rem][0];
                    else
                        curr[j][0] += prev[rem][0];
                }
            }
            // Copy curr to prev for the next iteration
            for (int j = 0; j < K; j++) {
                prev[j][0] = curr[j][0];
                prev[j][1] = curr[j][1];
                curr[j][0] = 0;
                curr[j][1] = 0;
            }
        }
 
        return prev[sum][1] + prev[sum][0];
    }
 
    public static void main(String[] args) {
        int N = 2, K = 7;
 
        System.out.println(countNum(N, 0, K));
    }
}
 
// This code is contributed by Tapesh(tapeshdua420)

                    

Python3

# Python implementation:
def countNum(N, sum, K):
    prev = [[0, 0] for _ in range(K)]
    curr = [[0, 0] for _ in range(K)]
 
    # Base case
    prev[0][0] = 1
 
    for i in range(1, N+1):
        for j in range(K):
            for k in range(int(i == 1), 10): # skip leading zeroes
                rem = (j - k % K + K) % K
 
                curr[j][1] += prev[rem][1]
                if k > 0:
                    curr[j][1] += prev[rem][0]
                else:
                    curr[j][0] += prev[rem][0]
 
        # Copy curr to prev for the next iteration
        for j in range(K):
            prev[j][0] = curr[j][0]
            prev[j][1] = curr[j][1]
            curr[j][0] = 0
            curr[j][1] = 0
 
    return prev[sum][1] + prev[sum][0]
 
N = 2
K = 7
 
print(countNum(N, 0, K))
 
# This code is contributed by Tapesh(tapeshdu420)

                    

C#

// C# implementation
using System;
 
class MainClass {
    public static int CountNum(int N, int sum, int K) {
        int[,] prev = new int[K, 2];
        int[,] curr = new int[K, 2];
 
        // Base case
        prev[0, 0] = 1;
 
        for (int i = 1; i <= N; i++) {
            for (int j = 0; j < K; j++) {
                for (int k = (i == 1) ? 1 : 0; k <= 9; k++) { // skip leading zeroes
                    int rem = (j - k % K + K) % K;
 
                    curr[j, 1] += prev[rem, 1];
                    if (k > 0)
                        curr[j, 1] += prev[rem, 0];
                    else
                        curr[j, 0] += prev[rem, 0];
                }
            }
            // Copy curr to prev for the next iteration
            for (int j = 0; j < K; j++) {
                prev[j, 0] = curr[j, 0];
                prev[j, 1] = curr[j, 1];
                curr[j, 0] = 0;
                curr[j, 1] = 0;
            }
        }
 
        return prev[sum, 1] + prev[sum, 0];
    }
 
    public static void Main(string[] args) {
        int N = 2, K = 7;
 
        Console.WriteLine(CountNum(N, 0, K));
    }
}
 
// This code is contributed by Sakshi

                    

Javascript

function countNum(N, sum, K) {
    const prev = new Array(K).fill(0).map(() => new Array(2).fill(0));
    const curr = new Array(K).fill(0).map(() => new Array(2).fill(0));
 
    // Base case
    prev[0][0] = 1;
 
    for (let i = 1; i <= N; i++) {
        for (let j = 0; j < K; j++) {
            for (let k = (i === 1) ? 1 : 0; k <= 9; k++) { // skip leading zeroes
                const rem = (j - (k % K) + K) % K;
 
                curr[j][1] += prev[rem][1];
                if (k > 0) {
                    curr[j][1] += prev[rem][0];
                } else {
                    curr[j][0] += prev[rem][0];
                }
            }
        }
        // Copy curr to prev for the next iteration
        for (let j = 0; j < K; j++) {
            prev[j][0] = curr[j][0];
            prev[j][1] = curr[j][1];
            curr[j][0] = 0;
            curr[j][1] = 0;
        }
    }
 
    return prev[sum][1] + prev[sum][0];
}
 
const N = 2;
const K = 7;
 
console.log(countNum(N, 0, K));
 
// This code is contributed by shivamgupta0987654321

                    

Output
12








Time Complexity: O(10*N*K)

Auxiliary Space: O(K)





Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads