Count of integers from the range [0, N] whose digit sum is a multiple of K - GeeksforGeeks

15 Jun, 2021
Given two integers N and K, the task is to calculate the number of integers in the range [0, N] whose digit sum is a multiple of K. The answer could be large, so print the answer modulo 109 +7.
Examples:  
Input: N = 10, K = 5 Output: 2 0 and 5 are the only possible integers.
Input: N = 30, K = 4 Output: 7  
Naive Approach: For small value of N, loop through the range [0, N] and check if the sum of the digits of the numbers are multiples of K or not. 
Efficient Approach: The idea is to use digit dp to solve this problem. Subproblems iterating through all index values from the left or most significant digit(MSD) in the given integer will be solved and for each index, store the number of ways such that (sum of digits upto current index) mod K to be zero. The dp states will be: 
dp[idx][sum][tight] idx = position, it tells about the index value from left in the given integer sum = sum of digits mod k, This parameter will store the (sum of digits mod k) in the generated integer from most significant digit(MSD) to p tight = flag if the current value is crossing the range (1, n) or not For unrestricted range tight = 0 For restricted range tight = 1 
Let’s say we are at the MSD having index idx. So initially the sum will be 0. At every position, set a limit that is always in the range [0, 9]. Therefore, fill the digit at index by the digits in its range from 0 to limit and fetch the answer from the next state having index = idx + 1 and new_tight for next state is calculated separately. The dp state definition will be: 
dp[idx][sum][tight] += dp[idx + 1][(sum + d) % k][new_tight] for d in [0, limit]  
Below is the implementation of the above approach: 
C++
Java
Python 3
C#
Javascript
// C++ implementation of the approach#include <bits/stdc++.h>using namespace std; #define MAX 100005#define MOD 1000000007 // To store the states of the dpint dp[MAX][101][2]; // Function to return the count of numbers// from the range [0, n] whose digit sum// is a multiple of k using bottom-up dpint countNum(int idx, int sum, int tight,             vector<int> num, int len, int k){    if (len == idx) {        if (sum == 0)            return 1;        else            return 0;    }    if (dp[idx][sum][tight] != -1)        return dp[idx][sum][tight];    int res = 0, limit;     // The digit in this index can    // only be from [0, num[idx]]    if (tight == 0) {        limit = num[idx];    }     // The digit in this index can    // be anything from [0, 9]    else {        limit = 9;    }    for (int i = 0; i <= limit; i++) {         // new_tight is the flag value        // for the next position        int new_tight = tight;        if (tight == 0 && i < limit)            new_tight = 1;        res += countNum(idx + 1,                        (sum + i) % k, new_tight,                        num, len, k);        res %= MOD;    }     // res can't be negative    if (res < 0)        res += MOD;    return dp[idx][sum][tight] = res;} // Function to process the string to// a vector of digits from MSD to LSDvector<int> process(string s){    vector<int> num;    for (int i = 0; i < s.length(); i++) {        num.push_back(s[i] - '0');    }    return num;} // Driver codeint main(){     // For large input number n    string n = "98765432109876543210";     // Total number of digits in n    int len = n.length();     int k = 58;     // Clean dp table    memset(dp, -1, sizeof(dp));     // Process the string to a vector    // of digits from MSD to LSD    vector<int> num = process(n);     cout << countNum(0, 0, 0, num, len, k);     return 0;}
// Java implementation of the approachimport java.util.*; class GFG{ static final int MAX = 100005;static final int MOD = 1000000007; // To store the states of the dpstatic int [][][]dp = new int[MAX][101][2]; // Function to return the count of numbers// from the range [0, n] whose digit sum// is a multiple of k using bottom-up dpstatic int countNum(int idx, int sum, int tight,            Vector<Integer> num, int len, int k){    if (len == idx)    {        if (sum == 0)            return 1;        else            return 0;    }    if (dp[idx][sum][tight] != -1)        return dp[idx][sum][tight];    int res = 0, limit;     // The digit in this index can    // only be from [0, num[idx]]    if (tight == 0)    {        limit = num.get(idx);    }     // The digit in this index can    // be anything from [0, 9]    else    {        limit = 9;    }    for (int i = 0; i <= limit; i++)    {         // new_tight is the flag value        // for the next position        int new_tight = tight;        if (tight == 0 && i < limit)            new_tight = 1;        res += countNum(idx + 1,                        (sum + i) % k, new_tight,                        num, len, k);        res %= MOD;    }     // res can't be negative    if (res < 0)        res += MOD;    return dp[idx][sum][tight] = res;} // Function to process the String to// a vector of digits from MSD to LSDstatic Vector<Integer> process(String s){    Vector<Integer> num = new Vector<Integer>();    for (int i = 0; i < s.length(); i++)    {        num.add(s.charAt(i) - '0');    }    return num;} // Driver codepublic static void main(String[] args){     // For large input number n    String n = "98765432109876543210";     // Total number of digits in n    int len = n.length();     int k = 58;     // Clean dp table    for(int i = 0; i < MAX; i++)    {        for(int j = 0; j < 101; j++)        {            for(int l = 0; l < 2; l++)            dp[i][j][l] = -1;        }    }     // Process the String to a vector    // of digits from MSD to LSD    Vector<Integer> num = process(n);     System.out.print(countNum(0, 0, 0, num, len, k)); }} // This code is contributed by 29AjayKumar
# Python 3 implementation of the approachMAX = 10005MOD = 1000000007 # Function to return the count of numbers# from the range [0, n] whose digit sum# is a multiple of k using bottom-up dpdef countNum(idx, sum, tight, num, len1, k):    if (len1 == idx):        if (sum == 0):            return 1        else:            return 0    if (dp[idx][sum][tight] != -1):        return dp[idx][sum][tight]    res = 0     # The digit in this index can    # only be from [0, num[idx]]    if (tight == 0):        limit = num[idx]     # The digit in this index can    # be anything from [0, 9]    else:        limit = 9    for i in range(limit + 1):                 # new_tight is the flag value        # for the next position        new_tight = tight        if (tight == 0 and i < limit):            new_tight = 1        res += countNum(idx + 1,(sum + i) % k,                      new_tight, num, len1, k)        res %= MOD     # res can't be negative    if (res < 0):        res += MOD    dp[idx][sum][tight] = res    return dp[idx][sum][tight] # Function to process the string to# a vector of digits from MSD to LSDdef process(s):    num = []    for i in range(len(s)):        num.append(ord(s[i]) - ord('0'))    return num # Driver codeif __name__ == '__main__':         # For large input number n    n = "98765432109876543210"     # Total number of digits in n    len1 = len(n)     k = 58         # To store the states of the dp    dp = [[[-1 for i in range(2)]               for j in range(101)]               for k in range(MAX)]     # Process the string to a vector    # of digits from MSD to LSD    num = process(n)     print(countNum(0, 0, 0, num, len1, k)) # This code is contributed by Surendra_Gangwar
// C# implementation of the approachusing System;using System.Collections.Generic; class GFG{static readonly int MAX = 10005;static readonly int MOD = 1000000007; // To store the states of the dpstatic int [,,]dp = new int[MAX, 101, 2]; // Function to return the count of numbers// from the range [0, n] whose digit sum// is a multiple of k using bottom-up dpstatic int countNum(int idx, int sum, int tight,              List<int> num, int len, int k){    if (len == idx)    {        if (sum == 0)            return 1;        else            return 0;    }         if (dp[idx, sum, tight] != -1)        return dp[idx, sum, tight];    int res = 0, limit;     // The digit in this index can    // only be from [0, num[idx]]    if (tight == 0)    {        limit = num[idx];    }     // The digit in this index can    // be anything from [0, 9]    else    {        limit = 9;    }    for (int i = 0; i <= limit; i++)    {         // new_tight is the flag value        // for the next position        int new_tight = tight;        if (tight == 0 && i < limit)            new_tight = 1;        res += countNum(idx + 1,                       (sum + i) % k, new_tight,                        num, len, k);        res %= MOD;    }     // res can't be negative    if (res < 0)        res += MOD;    return dp[idx, sum, tight] = res;} // Function to process the String to// a vector of digits from MSD to LSDstatic List<int> process(String s){    List<int> num = new List<int>();    for (int i = 0; i < s.Length; i++)    {        num.Add(s[i] - '0');    }    return num;} // Driver codepublic static void Main(String[] args){     // For large input number n    String n = "98765432109876543210";     // Total number of digits in n    int len = n.Length;     int k = 58;     // Clean dp table    for(int i = 0; i < MAX; i++)    {        for(int j = 0; j < 101; j++)        {            for(int l = 0; l < 2; l++)            dp[i, j, l] = -1;        }    }     // Process the String to a vector    // of digits from MSD to LSD    List<int> num = process(n);     Console.Write(countNum(0, 0, 0, num, len, k));}} // This code is contributed by Rajput-Ji
<script> // Javascript implementation of the approach var MAX = 100005;var MOD = 1000000007; // To store the states of the dpvar dp = Array.from(Array(MAX), () => Array(101));for(var i =0; i<MAX; i++)        for(var j =0; j<101; j++)            dp[i][j] = new Array(2).fill(-1); // Function to return the count of numbers// from the range [0, n] whose digit sum// is a multiple of k using bottom-up dpfunction countNum(idx, sum, tight, num, len, k){    if (len == idx) {        if (sum == 0)            return 1;        else            return 0;    }    if (dp[idx][sum][tight] != -1)        return dp[idx][sum][tight];    var res = 0, limit;     // The digit in this index can    // only be from [0, num[idx]]    if (tight == 0) {        limit = num[idx];    }     // The digit in this index can    // be anything from [0, 9]    else {        limit = 9;    }    for (var i = 0; i <= limit; i++) {         // new_tight is the flag value        // for the next position        var new_tight = tight;        if (tight == 0 && i < limit)            new_tight = 1;        res += countNum(idx + 1,                        (sum + i) % k, new_tight,                        num, len, k);        res %= MOD;    }     // res can't be negative    if (res < 0)        res += MOD;    return dp[idx][sum][tight] = res;} // Function to process the string to// a vector of digits from MSD to LSDfunction process(s){    var num = [];    for (var i = 0; i < s.length; i++) {        num.push(s[i].charCodeAt(0) - '0'.charCodeAt(0));    }    return num;} // Driver code// For large input number nvar n = "98765432109876543210";// Total number of digits in nvar len = n.length;var k = 58;// Process the string to a vector// of digits from MSD to LSDvar num = process(n);document.write( countNum(0, 0, 0, num, len, k)); </script>
635270835
 
SURENDRA_GANGWAR
29AjayKumar
Rajput-Ji
importantly
digit-DP
Dynamic Programming
Dynamic Programming
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Maximum size square sub-matrix with all 1s
Optimal Substructure Property in Dynamic Programming | DP-2
Optimal Binary Search Tree | DP-24
Min Cost Path | DP-6
Maximum Subarray Sum using Divide and Conquer algorithm
Greedy approach vs Dynamic programming
Maximum sum such that no two elements are adjacent
Word Break Problem | DP-32
3 Different ways to print Fibonacci series in Java
Top 50 Dynamic Programming Coding Problems for Interviews