Kth number exceeding N whose sum of its digits divisible by M

Given the integers N, K and M, the task is to find the Kth number greater than N whose sum of digits is divisible by M.

Examples:

Input: N = 6, K = 5, M = 5
Output: 32
Explanation:
The number greater than N = 6 with the sum of their digits divisible by 5 are {14, 19, 23, 28, 32, …}. The Kth number i.e., the 5th number is 32.

Input: N = 40, K = 4,  M = 5 
Output: 55
Explanation:
The number greater than N = 40 with the sum of their digits divisible by 5 are {41, 46, 50, 55, …}. The Kth number i.e., the 4th number is 55.

Naive Approach: The simplest approach is to check every number greater than N and if the sum of its digits is divisible by M, increment the counter by 1. Keep checking the number until the counter becomes equal to K



Time Complexity: O(K)
Auxiliary Space: O(1)

Efficient Approach: The idea is to use Dynamic Programming and Binary Search. Follow the below steps to solve the problem:

  • First, create a recursive memorized function to find the total number of integers smaller than or equal to S having the sum of digits divisible by M as shown below:

 The dp transitions will be:

dp(S, index, sum, tight, M) = dp(index+1, (sum+i)%M, tight, M) where,

  • S is given limit for which all numbers smaller than or equal to S with the sum of digits divisible by M needs to be found.
  • index is the current index for which a digit needs to be placed.
  • sum takes the values from 0 to 4.
  • Base condition is, if index becomes greater than the length of S and sum is divisible by M, return 1.
  • M is the divisor.

If the previous digit already placed such that it becomes smaller than S then 

  • tight will become equal to 0.
  • i will iterate from 0 to 9.

If all the previous digits match with the corresponding digits in S, then

  • tight will become 1, which denotes that the number is still not become smaller than S.
  • i will iterate from 0 to digit S[index].
  • Now using Binary Search, where the lower limit will be N+1 and the upper limit will be some large integer.
  • Initialize a variable left for storing the total numbers smaller than or equal to N whose sum of digits is divisible by M.
  • Find the midpoint of the lower and the upper limit and then find the numbers smaller than or equal midpoint whose sum of digits is divisible by M using the above dp function. Let it be right.
  • If left + K is equals to right then, update the answer as mid and set the upper limit as midpoint – 1.
  • Otherwise, if left + K is smaller than right, set the upper limit as midpoint-1.
  • If left + K is greater than right, set the lower limit as midpoint+1.
  • Repeat the above steps, while the lower limit is smaller than or equal to the upper limit.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Initialize dp array
int dp[100000][100][2];
 
// Function to find the numbers <= S
// having digits sum divisible by M
int solve(string s, int index, int sum,
                    int tight, int z)
{
     
    // Base Case
    if (index >= s.size())
    {
        if (sum % z == 0)
            return 1;
             
        return 0;
    }
 
    // Visited state
    if (dp[index][sum][tight] != -1)
        return dp[index][sum][tight];
 
    // Store answer
    int ans = 0;
 
    // If number still does not
    // become smaller than S
    if (tight == 1)
    {
         
        // Find limit
        int l = s[index] - '0';
 
        // Iterate through all
        // the digits
        for(int i = 0; i <= l; i++)
        {
             
            // If current digit is limit
            if (i == l)
            {
                ans += solve(s, index + 1,
                                 (sum + i) % z, 1, z);
            }
 
            // Number becomes smaller than S
            else {
                ans += solve(s, index + 1,
                                 (sum + i) % z, 0, z);
            }
        }
    }
    else
    {
         
        // If number already becomes
        // smaller than S
        for(int i = 0; i <= 9; i++)
            ans += solve(s, index + 1,
                             (sum + i) % z, 0, z);
    }
 
    // Return and store the answer
    // for the current state
    return dp[index][sum][tight] = ans;
}
 
// Function to find the Kth number
// > N whose sum of the digits is
// divisible by M
int search(int n, int k, int z)
{
     
    // Initialize lower limit
    int low = n + 1;
 
    // Initialize upper limit
    int high = 1e9;
 
    // Mask dp states unvisited
    memset(dp, -1, sizeof(dp));
 
    // Numbers <= N except 0 with
    // digits sum divisible by M
    int left = solve(to_string(n),
                     0, 0, 1, z) - 1;
 
    // Initialize answer with -1
    int ans = -1;
    while (low <= high)
    {
         
        // Calculate mid
        int mid = low + (high - low) / 2;
 
        // Mark dp states unvisited
        memset(dp, -1, sizeof(dp));
 
        // Numbers < mid with digits
        // sum divisible by M
        int right = solve(to_string(mid),
                          0, 0, 1, z) - 1;
 
        // If the current mid is
        // satisfy the condition
        if (left + k == right)
        {
             
            // Might be the answer
            ans = mid;
 
            // Update upper limit
            high = mid - 1;
        }
        else if (left + k < right)
        {
             
            // Update upper limit
            high = mid - 1;
        }
        else
        {
             
            // Update lower limit
            low = mid + 1;
        }
    }
 
    // Return the answer
    return ans;
}
 
// Driver Code
int main()
{
     
    // Given N, K, and M
    int N = 40;
    int K = 4;
    int M = 2;
     
    // Function Call
    cout << search(N, K, M) << endl;
}
 
// This code is contributed by bolliranadheer

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program for the above approach
 
import java.util.*;
public class Main {
 
    static int dp[][][];
 
    // Function to find the Kth number
    // > N whose sum of the digits is
    // divisible by M
    public static int search(
        int n, int k, int z)
    {
 
        // Initialize dp array
        dp = new int[100000 + 1][z][2];
 
        // Initialize lower limit
        int low = n + 1;
 
        // Initialize upper limit
        int high = Integer.MAX_VALUE / 2;
 
        // Mask dp states unvisited
        clear();
 
        // Numbers <= N except 0 with
        // digits sum divisible by M
        int left = solve(n + "", 0,
                         0, 1, z)
                   - 1;
 
        // Initialize answer with -1
        int ans = -1;
        while (low <= high) {
 
            // Calculate mid
            int mid = low + (high - low) / 2;
 
            // Mark dp states unvisited
            clear();
 
            // Numbers < mid with digits
            // sum divisible by M
            int right = solve(mid + "", 0,
                              0, 1, z)
                        - 1;
 
            // If the current mid is
            // satisfy the condition
            if (left + k == right) {
 
                // Might be the answer
                ans = mid;
 
                // Update upper limit
                high = mid - 1;
            }
            else if (left + k < right) {
 
                // Update upper limit
                high = mid - 1;
            }
            else {
 
                // Update lower limit
                low = mid + 1;
            }
        }
 
        // Return the answer
        return ans;
    }
 
    // Function to find the numbers <= S
    // having digits sum divisible by M
    public static int solve(
        String s, int index, int sum,
        int tight, int z)
    {
        // Base Case
        if (index >= s.length()) {
            if (sum % z == 0)
                return 1;
            return 0;
        }
 
        // Visited state
        if (dp[index][sum][tight] != -1)
            return dp[index][sum][tight];
 
        // Store answer
        int ans = 0;
 
        // If number still does not
        // become smaller than S
        if (tight == 1) {
 
            // Find limit
            int l = s.charAt(index) - '0';
 
            // Iterate through all
            // the digits
            for (int i = 0; i <= l; i++) {
 
                // If current digit is limit
                if (i == l) {
                    ans += solve(s, index + 1,
                                 (sum + i) % z,
                                 1, z);
                }
 
                // Number becomes smaller than S
                else {
                    ans += solve(s, index + 1,
                                 (sum + i) % z,
                                 0, z);
                }
            }
        }
        else {
 
            // If number already becomes
            // smaller than S
            for (int i = 0; i <= 9; i++)
                ans += solve(s, index + 1,
                             (sum + i) % z, 0,
                             z);
        }
 
        // Return and store the answer
        // for the current state
        return dp[index][sum][tight] = ans;
    }
 
    // Function to clear the states
    public static void clear()
    {
        for (int i[][] : dp) {
            for (int j[] : i)
                Arrays.fill(j, -1);
        }
    }
 
    // Driver Code
    public static void main(String args[])
    {
        // Given N, K, and M
        int N = 40;
        int K = 4;
        int M = 2;
 
        // Function Call
        System.out.println(search(N, K, M));
    }
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python program for the
# above approach
 
# Initialize dp array
dp = [[[]]]
 
# Function to find the
# numbers <= S having
# digits sum divisible
# by M
def solve(s, index,
          sum,tight, z):
 
    # Base Case
    if (index >= len(s)):   
        if (sum % z == 0):
            return 1
 
        return 0
 
    # Visited state
    if (dp[index][sum][tight] != -1):
        return dp[index][sum][tight]
 
    # Store answer
    ans = 0
 
    # If number still does not
    # become smaller than S
    if(tight == 1):
 
        # Find limit
        l = int(ord(s[index]) -
                ord('0'))
 
        # Iterate through all
        # the digits
        for i in range(0, l + 1):
             
            # If current digit is
            # limit
            if (i == l):
             
                ans += solve(s, index + 1,
                            (sum + i) % z,
                             1, z)
             
            # Number becomes smaller
            # than S
            else:
                ans += solve(s, index + 1,
                            (sum + i) % z,
                             0, z)
 
    else:
     
        # If number already becomes
        # smaller than S
        for i in range(0,10):
         
            ans += solve(s, index + 1,
                        (sum + i) % z,
                         0, z)
     
    # Return and store the answer
    # for the current state
    dp[index][sum][tight] = ans
    return ans
 
# Function to find the Kth number
# > N whose sum of the digits is
# divisible by M
def search(n, k, z):
 
    global dp
    dp = [[[-1, -1] for j in range(z)]
                    for i in range(100001)]
 
    # Initialize lower limit
    low = n + 1
 
    # Initialize upper limit
    high = 1000000009
 
    # Numbers <= N except 0 with
    # digits sum divisible by M
    left = solve(str(n), 0,
                 0, 1, z) - 1
 
    # Initialize answer with -1
    ans = -1
    while (low <= high):
 
        # Calculate mid
        mid = low + (high -
                     low) // 2
 
        # Mark dp states unvisited
        dp = [[[-1, -1] for j in range(z)]
                        for i in range(100000)]
 
        # Numbers < mid with digits
        # sum divisible by M
        right = solve(str(mid), 0,
                      0, 1, z) - 1
 
        # If the current mid is
        # satisfy the condition
        if (left + k == right):
 
            # Might be the answer
            ans = mid
 
            # Update upper limit
            high = mid - 1
         
        elif (left + k < right):
         
            # Update upper limit
            high = mid - 1
         
        else:
 
            # Update lower limit
            low = mid + 1
 
    # Return the answer
    return ans
 
# Driver Code
if __name__ == "__main__":
     
    # Given N, K, and M
    N = 40
    K = 4
    M = 2
 
    # Function Call
    print(search(N, K, M))
 
# This code is contributed by Rutvik_56

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program for the above approach
using System;
 
class GFG{
 
static int [,,]dp;
 
// Function to find the Kth number
// > N whose sum of the digits is
// divisible by M
public static int search(int n, int k,
                         int z)
{
     
    // Initialize dp array
    dp = new int[100000 + 1, z, 2];
 
    // Initialize lower limit
    int low = n + 1;
 
    // Initialize upper limit
    int high = int.MaxValue / 2;
 
    // Mask dp states unvisited
    Clear(z);
 
    // Numbers <= N except 0 with
    // digits sum divisible by M
    int left = solve(n + "", 0,
                     0, 1, z) - 1;
 
    // Initialize answer with -1
    int ans = -1;
    while (low <= high)
    {
         
        // Calculate mid
        int mid = low + (high - low) / 2;
         
        // Mark dp states unvisited
        Clear(z);
         
        // Numbers < mid with digits
        // sum divisible by M
        int right = solve(mid + "", 0,
                          0, 1, z) - 1;
 
        // If the current mid is
        // satisfy the condition
        if (left + k == right)
        {
             
            // Might be the answer
            ans = mid;
 
            // Update upper limit
            high = mid - 1;
        }
        else if (left + k < right)
        {
             
            // Update upper limit
            high = mid - 1;
        }
        else
        {
             
            // Update lower limit
            low = mid + 1;
        }
    }
     
    // Return the answer
    return ans;
}
 
// Function to find the numbers <= S
// having digits sum divisible by M
public static int solve(String s, int index,
                        int sum, int tight,
                        int z)
{
     
    // Base Case
    if (index >= s.Length)
    {
        if (sum % z == 0)
            return 1;
             
        return 0;
    }
 
    // Visited state
    if (dp[index, sum, tight] != -1)
        return dp[index, sum, tight];
 
    // Store answer
    int ans = 0;
 
    // If number still does not
    // become smaller than S
    if (tight == 1)
    {
         
        // Find limit
        int l = s[index] - '0';
 
        // Iterate through all
        // the digits
        for(int i = 0; i <= l; i++)
        {
             
            // If current digit is limit
            if (i == l)
            {
                ans += solve(s, index + 1,
                            (sum + i) % z,
                             1, z);
            }
             
            // Number becomes smaller than S
            else
            {
                ans += solve(s, index + 1,
                            (sum + i) % z,
                             0, z);
            }
        }
    }
    else
    {
         
        // If number already becomes
        // smaller than S
        for(int i = 0; i <= 9; i++)
            ans += solve(s, index + 1,
                        (sum + i) % z, 0,
                         z);
    }
     
    // Return and store the answer
    // for the current state
    return dp[index, sum, tight] = ans;
}
 
// Function to clear the states
public static void Clear(int z)
{
    for(int i = 0; i < 100001; i++)
    {
        for(int j = 0; j < z; j++)
        {
            for(int l = 0; l < 2; l++)
                dp[i, j, l] = -1;
        }
    }
}
 
// Driver Code
public static void Main(String []args)
{
     
    // Given N, K, and M
    int N = 40;
    int K = 4;
    int M = 2;
     
    // Function Call
    Console.WriteLine(search(N, K, M));
}
}
 
// This code is contributed by gauravrajput1

chevron_right


Output

48

Time Complexity: O(log(INT_MAX))
Auxiliary Space: O(K * M * log(INT_MAX))

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Recommended Posts:


Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.