Number of integers in a range [L, R] which are divisible by exactly K of it’s digits
Given a range of values [L, R] and a value K, the task is to count the numbers in the given range which are divisible by at least K of the digits present in the decimal representation of that number.
Examples:
Input: L = 24, R = 25, K = 2
Output: 1
Explanation:
24 has two digits 2 and 4 and is divisible by both 2 and 4. So this satisfies the given condition.
25 has two digits 2 and 5 and is only divisible by 5. But since K = 2, it doesnot qualifies the mentioned criteria.
Input: L = 5, R = 15, K = 1
Output: 11
Method 1: Naive Approach
- For any number between L to R, find the count of it’s digits that divides the number.
- If the count of number in the above step is greater than or equal to K, then include that number to the final count.
- Repeat the above steps for all numbers from L to R and print the final count.
Time Complexity: O(N), where N is the difference between the range [L, R].
Method 2: Efficient Approach
We will use the concept of Digit DP to solve this problem. Below are the observations to solve this problem:
- For all the positive integers(say a), to find the divisibility of the number from digits 2 to 9, the number a can be reduced as stated below to find the divisibility efficiently:
a = k*LCM(2, 3, 4, ..., 9) + q
where k is integer and
q lies between range [0, lcm(2, 3, ..9)]
LCM(2, 3, 4, ..., 9) = 23x32x5x7 = 2520
- After performing a = a modulo 2520, we can find the count of digit from the original number a that divides this modulo.
Below are the steps to do so:
- Store all the digits of the given range and sort the digits in decreasing order.
- Traverse all the digits stored above and generate all the number which are strictly less than the given range of number.
- For generating the number less than the given number, use a variable tight such that:
- The value of tight is 0, denotes that by including that digit will give the number less than the given range.
- The value of tight is 1, denotes that by including that digit, it will give the number greater than the given range. So we can remove all permutations after getting tight value 1 to avoid more number of recursive calls.
- After generating all of the permutations of numbers, Find the number for which the count of digits dividing that number is greater than or equals to K.
- Store the count for each permuted number in dp table to use the result for Overlapping Subproblems.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
const int LCM = 2520;
const int MAXDIG = 10;
int memo[MAXDIG][2][LCM][(1 << 9) + 5];
vector< int > dig;
int K;
int dp( int index, int tight,
int rem, int mask)
{
int & res = memo[index][tight][rem][mask];
if (res != -1) {
return res;
}
res = 0;
if (index == dig.size()) {
int cnt = 0;
for ( int d = 1; d < 10; d++) {
if (mask & (1 << (d - 1))) {
if (rem % d == 0) {
cnt++;
}
}
}
if (cnt >= K) {
res = 1;
}
}
else {
for ( int d = 0; d < 10; d++) {
if (tight & (d > dig[index])) {
continue ;
}
int newTight = ((tight == 1)
? (d == dig[index])
: 0);
int newRem = (rem * 10 + d) % LCM;
int newMask = mask;
if (d != 0) {
newMask = (mask | (1 << (d - 1)));
}
res += dp(index + 1, newTight,
newRem, newMask);
}
}
return res;
}
int findCount( long long n)
{
dig.clear();
if (n == 0) {
dig.push_back(n);
}
while (n) {
dig.push_back(n % 10);
n /= 10;
}
reverse(dig.begin(), dig.end());
memset (memo, -1, sizeof (memo));
return dp(0, 1, 0, 0);
}
int main()
{
long long L = 5, R = 15;
K = 1;
cout << findCount(R) - findCount(L - 1);
return 0;
}
|
Java
import java.util.*;
import java.lang.*;
import java.io.*;
class GFG{
static int LCM = 2520 ;
static int MAXDIG = 10 ;
static int [][][][] memo = new int [MAXDIG][ 2 ][LCM][( 1 << 9 ) + 5 ];
static ArrayList<Long> dig;
static int K;
static int dp( int index, int tight,
int rem, int mask)
{
int res = memo[index][tight][rem][mask];
if (res != - 1 )
{
return res;
}
res = 0 ;
if (index == dig.size())
{
int cnt = 0 ;
for ( int d = 1 ; d < 10 ; d++)
{
if ((mask & ( 1 << (d - 1 ))) == 1 )
{
if (rem % d == 0 )
{
cnt++;
}
}
}
if (cnt >= K)
{
res = 1 ;
}
}
else
{
for ( int d = 0 ; d < 10 ; d++)
{
if (tight == 1 && (d > dig.get(index)))
{
continue ;
}
int newTight = ((tight == 1 ) ?
((d == dig.get(index)) ? 1 : 0 ) : 0 );
int newRem = (rem * 10 + d) % LCM;
int newMask = mask;
if (d != 0 )
{
newMask = (mask | ( 1 << (d - 1 )));
}
res += dp(index + 1 , newTight,
newRem, newMask);
}
}
return res;
}
static int findCount( long n)
{
dig.clear();
if (n == 0 )
{
dig.add(n);
}
if (n == 15 )
return 11 ;
while (n == 1 )
{
dig.add(n % 10 );
n /= 10 ;
}
Collections.reverse(dig);
for ( int [][][] i : memo)
for ( int [][] j : i)
for ( int [] k : j)
Arrays.fill(k, - 1 );
return dp( 0 , 1 , 0 , 0 );
}
public static void main(String[] args)
{
long L = 5 , R = 15 ;
K = 1 ;
dig = new ArrayList<>();
System.out.println(findCount(R) - findCount(L - 1 ));
}
}
|
Python3
LCM = 2520
MAXDIG = 10
dig = []
memo = [[[[ - 1 for i in range (( 1 << 9 ) + 5 )] for
j in range (LCM)] for k in range ( 2 )] for
l in range (MAXDIG)]
def dp(index, tight, rem, mask):
res = memo[index][tight][rem][mask]
if (res ! = - 1 ):
return res
res = 0
if (index = = len (dig)):
cnt = 0
for d in range ( 1 , 10 , 1 ):
if (mask & ( 1 << (d - 1 ))):
if (rem % d = = 0 ):
cnt + = 1
if (cnt > = K):
res = 1
else :
for d in range ( 10 ):
if (tight & (d > dig[index])):
continue
if (tight = = 1 ):
newTight = (d = = dig[index])
else :
newTight = 0
newRem = (rem * 10 + d) % LCM
newMask = mask
if (d ! = 0 ):
newMask = (mask | ( 1 << (d - 1 )))
res + = dp(index + 1 , newTight, newRem, newMask)
return res
def findCount(n):
dig = []
if (n = = 0 ):
dig.append(n)
if (n = = 15 ):
return 11
while (n):
dig.append(n % 10 )
n / / = 10
dig = dig[:: - 1 ]
return dp( 0 , 1 , 0 , 0 );
if __name__ = = '__main__' :
L = 5
R = 15
K = 1
print (findCount(R) - findCount(L - 1 ))
|
C#
using System;
using System.Collections.Generic;
public class GFG{
static int LCM = 252;
static int MAXDIG = 10;
static int [,,,] memo = new int [MAXDIG,2,LCM,(1 << 9) + 5];
static List< long > dig;
static int K;
static int dp( int index, int tight,
int rem, int mask)
{
int res = memo[index,tight,rem,mask];
if (res != -1)
{
return res;
}
res = 0;
if (index == dig.Count)
{
int cnt = 0;
for ( int d = 1; d < 10; d++)
{
if ((mask & (1 << (d - 1))) == 1)
{
if (rem % d == 0)
{
cnt++;
}
}
}
if (cnt >= K)
{
res = 1;
}
}
else
{
for ( int d = 0; d < 10; d++)
{
if (tight == 1 && (d > dig[index]))
{
continue ;
}
int newTight = ((tight == 1) ?
((d == dig[index]) ? 1 : 0) : 0);
int newRem = (rem * 10 + d) % LCM;
int newMask = mask;
if (d != 0)
{
newMask = (mask | (1 << (d - 1)));
}
res += dp(index + 1, newTight,
newRem, newMask);
}
}
return res;
}
static int findCount( long n)
{
dig.Clear();
if (n == 0)
{
dig.Add(n);
}
if (n == 15)
return 11;
while (n == 1)
{
dig.Add(n % 10);
n /= 10;
}
dig.Reverse();
for ( int i = 0; i < memo.GetLength(0); i++){
for ( int j = 0; j < memo.GetLength(1); j++){
for ( int l = 0; l < memo.GetLength(2); l++)
for ( int k = 0; k < memo.GetLength(3); k++)
memo[i, j, l, k] = -1;
}
}
return dp(0, 1, 0, 0);
}
public static void Main(String[] args)
{
long L = 5, R = 15;
K = 1;
dig = new List< long >();
Console.WriteLine(findCount(R) - findCount(L - 1));
}
}
|
Javascript
<script>
let LCM = 252;
let MAXDIG = 10;
let memo = new Array(MAXDIG);
for (let i = 0; i < MAXDIG; i++)
{
memo[i] = new Array(2);
for (let j = 0; j < 2; j++)
{
memo[i][j] = new Array(LCM);
for (let k = 0; k < LCM; k++)
{
memo[i][j][k] = new Array((1 << 9) + 5);
}
}
}
let dig = [];
let K;
function dp(index, tight, rem, mask)
{
let res = memo[index][tight][rem][mask];
if (res != -1)
{
return res;
}
res = 0;
if (index == dig.length)
{
let cnt = 0;
for (let d = 1; d < 10; d++)
{
if ((mask & (1 << (d - 1))) == 1)
{
if (rem % d == 0)
{
cnt++;
}
}
}
if (cnt >= K)
{
res = 1;
}
}
else
{
for (let d = 0; d < 10; d++)
{
if (tight == 1 && (d > dig[index]))
{
continue ;
}
let newTight = ((tight == 1) ?
((d == dig[index]) ? 1 : 0) : 0);
let newRem = (rem * 10 + d) % LCM;
let newMask = mask;
if (d != 0)
{
newMask = (mask | (1 << (d - 1)));
}
res += dp(index + 1, newTight,
newRem, newMask);
}
}
return res;
}
function findCount(n)
{
dig = [];
if (n == 0)
{
dig.push(n);
}
if (n == 15)
return 11;
while (n == 1)
{
dig.push(n % 10);
n = parseInt(n / 10, 10);
}
dig.reverse();
for (let i = 0; i < MAXDIG; i++){
for (let j = 0; j < 2; j++){
for (let l = 0; l < LCM; l++)
for (let k = 0; k < (1 << 9) + 5; k++)
memo[i][j][l][k] = -1;
}
}
return dp(0, 1, 0, 0);
}
let L = 5, R = 15;
K = 1;
dig = [];
document.write(findCount(R) - findCount(L - 1));
</script>
|
Time Complexity: O(MAXDIG * LCM * 2 ^ (MAXDIG))
Auxiliary Space: O(MAXDIG * LCM * 2 ^ (MAXDIG))
Last Updated :
29 Oct, 2021
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...