 GeeksforGeeks App
Open App Browser
Continue

# Count numbers with exactly K non-zero digits and distinct odd digit sum

Given an Integer N, and a number K, the task is to find out the total numbers from 0 to N which have exactly K non zero digits and the sum of those digits should be odd and that sum should be distinct. The number N can be as large as 10^18.
Examples:

Input : N = 10, K = 1
Output :
The numbers which follow the conditions are ->
1, 3, 5, 7 and 9
The digit sum of 10 that is (1+0) = 1 is also odd, but 1 is already included in our count.
Input : N = 100, K = 2
Output : 8

Prerequisites: Digit-DP
Naive Approach:
A naive approach for linear traversing in O(N) of all elements from 0 to N and calculating sum of digits in log(n) where n is the number of digits in that number will fail for large inputs of N.
Efficient Approach:

1. We can use Dynamic Programming and it’s very useful technique that is digit-dp to solve this problem.

2. So instead of keeping a record of non-zero integers, we keep a record of zeroes we can keep at different indices, idx in variable K. The number of zeroes we can keep can be found initially by subtracting K with the number of digits in N.

3. We keep all the digits of N into a vector say, digits

4. Now, we calculate range of elements we can keep at index idx by analysing K.
• Suppose at index idx, we are left with K = 1 (A Non-zero value), then our range to put elements is [0, j] where j is the upper bound decided by the tight value obtained from the current index of the digit from vector digits.

• If at idx, we are left with K = 0, then our range becomes [1, j] because we can’t put in 0 there.

5. Now, also take a parameter that is sum, which will calculate the sum of digits of a number till the base case hits successfully.

6. Also, a boolean map is used which will store all the odd sums calculated already, so it gives distinct odd sums.

7. The recurrence will be: where j = digits[idx] if tight = 0, else j = 9

8. Base Case:
• When idx = digits.size(), K == 0 and sum is odd.
We mark the sum as true and return 1 else return 0.

• If idx > digits.size() then return 0.

So we create a DP table say DP[idx][K][tight][sum] which will store our result from the recurrence above and return the count by memoizing it to this DP table.
Below is the implementation of the above approach:

## C++

 // C++ program to Count the numbers having// exactly K non-zero digits and sum// of digits are odd and distinct.#include using namespace std; // To store digits of Nvector<int> digits; // visited mapbool vis = { false }; // DP Tableint dp; // Push all the digits of N into// digits vectorvoid ConvertIntoDigit(int n){    while (n) {        int dig = n % 10;        digits.push_back(dig);        n /= 10;    }    reverse(digits.begin(), digits.end());} // Function returns the countint solve(int idx, int k,          int tight, int sum){    // If desired number is formed    // whose sum is odd    if (idx == digits.size()        && k == 0 && sum & 1) {        // If it is not present in map,        // mark it as true and return 1        if (!vis[sum]) {            vis[sum] = 1;            return 1;        }        // Sum is present in map already        return 0;    }     // Desired result not found    if (idx > digits.size()) {        return 0;    }     // If that state is already calculated    // just return that state value    if (dp[idx][k][tight][sum]) {        return dp[idx][k][tight][sum];    }     // Upper limit    int j;    if (tight == 0) {        j = digits[idx];    }    else {        j = 9;    }     // To store the count of    // desired numbers    int cnt = 0;     // If k is non-zero, i ranges from    // 0 to j else [1, j]    for (int i = (k ? 0 : 1);         i <= j; i++) {        int newtight = tight;         if (i < j) {            newtight = 1;        }         // If current digit is 0, decrement        // k and recurse sum is not changed        // as we are just adding 0 that        // makes no difference        if (i == 0)            cnt += solve(idx + 1, k - 1,                         newtight, sum);         // If i is non zero, then k remains        // unchanged and value is added to sum        else            cnt += solve(idx + 1, k, newtight,                         sum + i);    }     // Memoize and return    return dp[idx][k][tight][sum] = cnt;} // Driver codeint main(){     // K is the number of exact non-zero    // elements to have in number    int N, k;    N = 169, k = 2;     // break N into its digits    ConvertIntoDigit(N);     // We keep record of 0s we need to    // place in the number    k = digits.size() - k;    cout << solve(0, k, 0, 0);}

## Java

 // Java program to count the numbers having// exactly K non-zero digits and sum// of digits are odd and distinct.import java.util.*; class GFG{ // To store digits of Nstatic Vector digits = new Vector(); // visited mapstatic boolean []vis = new boolean; // DP Tablestatic int [][][][]dp = new int; // Push all the digits of N into// digits vectorstatic void ConvertIntoDigit(int n){    while (n > 0)    {        int dig = n % 10;        digits.add(dig);        n /= 10;    }    Collections.reverse(digits);} // Function returns the countstatic int solve(int idx, int k,                 int tight, int sum){         // If desired number is formed    // whose sum is odd    if (idx == digits.size() &&          k == 0 && sum % 2 == 1)    {                 // If it is not present in map,        // mark it as true and return 1        if (!vis[sum])        {            vis[sum] = true;            return 1;        }                 // Sum is present in map already        return 0;    }     // Desired result not found    if (idx > digits.size())    {        return 0;    }     // If that state is already calculated    // just return that state value    if (dp[idx][k][tight][sum] > 0)    {        return dp[idx][k][tight][sum];    }     // Upper limit    int j;    if (idx < digits.size() && tight == 0)    {        j = digits.get(idx);    }    else    {        j = 9;    }     // To store the count of    // desired numbers    int cnt = 0;     // If k is non-zero, i ranges from    // 0 to j else [1, j]    for(int i = (k > 0 ? 0 : 1); i <= j; i++)    {        int newtight = tight;         if (i < j)        {            newtight = 1;        }         // If current digit is 0, decrement        // k and recurse sum is not changed        // as we are just adding 0 that        // makes no difference        if (i == 0)            cnt += solve(idx + 1, k - 1,                         newtight, sum);         // If i is non zero, then k remains        // unchanged and value is added to sum        else            cnt += solve(idx + 1, k, newtight,                         sum + i);    }     // Memoize and return    return dp[idx][k][tight][sum] = cnt;} // Driver codepublic static void main(String[] args){     // K is the number of exact non-zero    // elements to have in number    int N, k;    N = 169; k = 2;     // break N into its digits    ConvertIntoDigit(N);     // We keep record of 0s we need to    // place in the number    k = digits.size() - k;         System.out.print(solve(0, k, 0, 0));}} // This code is contributed by amal kumar choubey

## Python3

 # Python3 program to Count the numbers having# exactly K non-zero digits and sum# of digits are odd and distinct.  # To store digits of Ndigits = []  # visited mapvis = [False for i in range(170)]  # DP Tabledp = [[[[0 for l in range(170)] for k in range(2)] for j in range(19)] for i in range(19)]  # Push all the digits of N into# digits vectordef ConvertIntoDigit(n):     while (n > 0):        dig = n % 10;        digits.append(dig);        n //= 10;    digits.reverse()     # Function returns the countdef solve(idx, k, tight, sum):     # If desired number is formed    # whose sum is odd    if (idx == len(digits) and k == 0 and sum % 2 == 1):                 # If it is not present in map,        # mark it as true and return 1        if (not vis[sum]):            vis[sum] = True;            return 1;                 # Sum is present in map already        return 0;         # Desired result not found    if (idx > len(digits)):        return 0;         # If that state is already calculated    # just return that state value    if (dp[idx][k][tight][sum]):        return dp[idx][k][tight][sum];         # Upper limit    j = 0;    if (idx<len(digits) and tight == 0):        j = digits[idx];         else:        j = 9;         # To store the count of    # desired numbers    cnt = 0;      # If k is non-zero, i ranges from    # 0 to j else [1, j]    for i in range(0 if k else 1, j + 1):        newtight = tight;          if (i < j):            newtight = 1;          # If current digit is 0, decrement        # k and recurse sum is not changed        # as we are just adding 0 that        # makes no difference        if (i == 0):            cnt += solve(idx + 1, k - 1, newtight, sum);          # If i is non zero, then k remains        # unchanged and value is added to sum        else:              cnt += solve(idx + 1, k, newtight, sum + i);         dp[idx][k][tight][sum] = cnt         # Memoize and return    return cnt; # Driver codeif __name__=='__main__':      # K is the number of exact non-zero    # elements to have in number    N = 169    k = 2;      # break N into its digits    ConvertIntoDigit(N);      # We keep record of 0s we need to    # place in the number    k = len(digits) - k;    print(solve(0, k, 0, 0)) # This code is contributed by rutvik_56.

## C#

 // C# program to count the numbers having// exactly K non-zero digits and sum// of digits are odd and distinct.using System;using System.Collections.Generic; class GFG{ // To store digits of Nstatic List<int> digits = new List<int>(); // visited mapstatic bool []vis = new bool; // DP Tablestatic int [,,,]dp = new int[ 19, 19, 2, 170 ]; // Push all the digits of N into// digits vectorstatic void ConvertIntoDigit(int n){    while (n > 0)    {        int dig = n % 10;        digits.Add(dig);        n /= 10;    }    digits.Reverse();} // Function returns the countstatic int solve(int idx, int k,                 int tight, int sum){         // If desired number is formed    // whose sum is odd    if (idx == digits.Count &&          k == 0 && sum % 2 == 1)    {                 // If it is not present in map,        // mark it as true and return 1        if (!vis[sum])        {            vis[sum] = true;            return 1;        }                 // Sum is present in map already        return 0;    }     // Desired result not found    if (idx > digits.Count)    {        return 0;    }     // If that state is already calculated    // just return that state value    if (dp[idx, k, tight, sum] > 0)    {        return dp[idx, k, tight, sum];    }     // Upper limit    int j;    if (idx < digits.Count && tight == 0)    {        j = digits[idx];    }    else    {        j = 9;    }     // To store the count of    // desired numbers    int cnt = 0;     // If k is non-zero, i ranges from    // 0 to j else [1, j]    for(int i = (k > 0 ? 0 : 1); i <= j; i++)    {        int newtight = tight;         if (i < j)        {            newtight = 1;        }         // If current digit is 0, decrement        // k and recurse sum is not changed        // as we are just adding 0 that        // makes no difference        if (i == 0)            cnt += solve(idx + 1, k - 1,                         newtight, sum);         // If i is non zero, then k remains        // unchanged and value is added to sum        else            cnt += solve(idx + 1, k, newtight,                         sum + i);    }     // Memoize and return    return dp[idx, k, tight, sum] = cnt;} // Driver codepublic static void Main(String[] args){         // K is the number of exact non-zero    // elements to have in number    int N, k;    N = 169; k = 2;     // break N into its digits    ConvertIntoDigit(N);     // We keep record of 0s we need to    // place in the number    k = digits.Count - k;         Console.Write(solve(0, k, 0, 0));}} // This code is contributed by amal kumar choubey

## Javascript

 

Output:

12

My Personal Notes arrow_drop_up