Open In App

Count Numbers in Range with difference between Sum of digits at even and odd positions as Prime

Given a range [L, R]. The task is to count the numbers in the range having difference between the sum of digits at even position and sum of digits at odd position is a Prime Number. Consider the position of least significant digit in the number as an odd position.
Examples: 
 

Input : L = 1, R = 50
Output : 6
Explanation : Only, 20, 30, 31, 41, 
42 and 50 are valid numbers. 

Input : L = 50, R = 100
Output : 18

 



Prerequisites: Digit DP
Approach: Firstly, if we are able to count the required numbers up to R i.e. in the range [0, R], we can easily reach our answer in the range [L, R] by solving for from zero to R and then subtracting the answer we get after solving from zero to L – 1. Now, we need to define the DP states.
DP States: 
 

Also, when we reach the base condition, we need to check whether the required difference is a prime number or not. Since the highest number in range is 1018, the maximum sum at either even or odd positions can be at max 9 times 9 and hence the maximum difference. So, we need to check only prime numbers only upto 100 at base condition.
Below is the implementation of the above approach: 
 






// C++ implementation of the above approach
 
#include <bits/stdc++.h>
using namespace std;
 
const int M = 18;
int a, b, dp[M][90][90][2];
 
// Prime numbers upto 100
int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23,
                29, 31, 37, 43, 47, 53, 59, 61,
                67, 71, 73, 79, 83, 89, 97 };
 
// Function to return the count of
// required numbers from 0 to num
int count(int pos, int even, int odd, int tight,
        vector<int> num)
{
    // Base Case
    if (pos == num.size()) {
        if (num.size() & 1)
            swap(odd, even);
        int d = even - odd;
 
        // check if the difference is equal
        // to any prime number
        for (int i = 0; i < 24; i++)
            if (d == prime[i])
                return 1;
                 
        return 0;
    }
 
    // If this result is already computed
    // simply return it
    if (dp[pos][even][odd][tight] != -1)
        return dp[pos][even][odd][tight];
 
    int ans = 0;
 
    // Maximum limit upto which we can place
    // digit. If tight is 1, means number has
    // already become smaller so we can place
    // any digit, otherwise num[pos]
    int limit = (tight ? 9 : num[pos]);
 
    for (int d = 0; d <= limit; d++) {
        int currF = tight, currEven = even;
        int currOdd = odd;
         
        if (d < num[pos])
            currF = 1;
 
        // If the current position is odd
        // add it to currOdd, otherwise to
        // currEven
        if (pos & 1)
            currOdd += d;
        else
            currEven += d;
             
        ans += count(pos + 1, currEven, currOdd,
                    currF, num);
    }
     
    return dp[pos][even][odd][tight] = ans;
}
 
// Function to convert x into its digit vector
// and uses count() function to return the
// required count
int solve(int x)
{
    vector<int> num;
     
    while (x) {
        num.push_back(x % 10);
        x /= 10;
    }
     
    reverse(num.begin(), num.end());
 
    // Initialize dp
    memset(dp, -1, sizeof(dp));
    return count(0, 0, 0, 0, num);
}
 
// Driver Code
int main()
{
    int L = 1, R = 50;
    cout << solve(R) - solve(L - 1) << endl;
 
    L = 50, R = 100;
    cout << solve(R) - solve(L - 1) << endl;
     
    return 0;
}




// Java implementation of the above approach
import java.util.*;
 
class GFG
{
 
static int M = 18;
static int a, b, dp[][][][] = new int[M][90][90][2];
 
// Prime numbers upto 100
static int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23,
                29, 31, 37, 43, 47, 53, 59, 61,
                67, 71, 73, 79, 83, 89, 97 };
 
// Function to return the count of
// required numbers from 0 to num
static int count(int pos, int even, int odd, int tight,
        Vector<Integer> num)
{
    // Base Case
    if (pos == num.size())
    {
        if ((num.size() & 1) != 0)
        {
            int t = odd;
            odd = even;
            even = t;
             
        }
        int d = even - odd;
 
        // check if the difference is equal
        // to any prime number
        for (int i = 0; i < 24; i++)
            if (d == prime[i])
                return 1;
                 
        return 0;
    }
 
    // If this result is already computed
    // simply return it
    if (dp[pos][even][odd][tight] != -1)
        return dp[pos][even][odd][tight];
 
    int ans = 0;
 
    // Maximum limit upto which we can place
    // digit. If tight is 1, means number has
    // already become smaller so we can place
    // any digit, otherwise num[pos]
    int limit = (tight != 0 ? 9 : num.get(pos));
 
    for (int d = 0; d <= limit; d++)
    {
        int currF = tight, currEven = even;
        int currOdd = odd;
         
        if (d < num.get(pos))
            currF = 1;
 
        // If the current position is odd
        // add it to currOdd, otherwise to
        // currEven
        if ((pos & 1) != 0)
            currOdd += d;
        else
            currEven += d;
             
        ans += count(pos + 1, currEven, currOdd,
                    currF, num);
    }
     
    return dp[pos][even][odd][tight] = ans;
}
 
// Function to convert x into its digit vector
// and uses count() function to return the
// required count
static int solve(int x)
{
    Vector<Integer> num = new Vector<Integer>();
     
    while (x != 0)
    {
        num.add(x % 10);
        x /= 10;
    }
     
    Collections.reverse(num);
 
    // Initialize dp
    for(int i = 0; i < dp.length; i++)
        for(int j = 0; j < dp[i].length; j++)
            for(int k = 0; k < dp[i][j].length; k++)
                for(int k1 = 0; k1 < dp[i][j][k].length; k1++)
                    dp[i][j][k][k1] = -1;
     
    return count(0, 0, 0, 0, num);
}
 
// Driver Code
public static void main(String args[])
{
    int L = 1, R = 50;
    System.out.println( solve(R) - solve(L - 1));
 
    L = 50; R = 100;
    System.out.println( solve(R) - solve(L - 1));
}
}
 
// This code is contributed by Arnab Kundu




# Python implementation of the above approach
 
M = 18
 
# Prime numbers upto 100
prime = [ 2, 3, 5, 7, 11, 13, 17, 19, 23,
        29, 31, 37, 43, 47, 53, 59, 61,
        67, 71, 73, 79, 83, 89, 97 ]
 
# Function to return the count of
# required numbers from 0 to num
def count(pos, even, odd, tight, num):
 
    # Base Case
    if pos == len(num):
        if len(num) & 1:
            odd, even = even, odd
 
        d = even - odd
 
        # check if the difference is equal
        # to any prime number
        for i in range(24):
            if d == prime[i]:
                return 1
        return 0
 
    # If this result is already computed
    # simply return it
    if dp[pos][even][odd][tight] != -1:
        return dp[pos][even][odd][tight]
 
    ans = 0
 
    # Maximum limit upto which we can place
    # digit. If tight is 1, means number has
    # already become smaller so we can place
    # any digit, otherwise num[pos]
    limit = 9 if tight else num[pos]
 
    for d in range(limit + 1):
        currF = tight
        currEven = even
        currOdd = odd
 
        if d < num[pos]:
            currF = 1
 
        # If the current position is odd
        # add it to currOdd, otherwise to
        # currEven
        if pos & 1:
            currOdd += d
        else:
            currEven += d
 
        ans += count(pos + 1, currEven, currOdd, currF, num)
 
    dp[pos][even][odd][tight] = ans
    return dp[pos][even][odd][tight]
 
# Function to convert x into its digit vector
# and uses count() function to return the
# required count
def solve(x):
    global dp
    num = []
    while x:
        num.append(x % 10)
        x //= 10
 
    num.reverse()
 
    # Initialize dp
    dp = [[[[-1, -1] for i in range(90)]
            for j in range(90)] for k in range(M)]
    return count(0, 0, 0, 0, num)
 
# Driver Code
if __name__ == "__main__":
    dp = []
 
    L = 1
    R = 50
    print(solve(R) - solve(L - 1))
 
    L = 50
    R = 100
    print(solve(R) - solve(L - 1))
 
# This code is contributed by
# sanjeev2552




// C# implementation of the above approach
using System;
using System.Collections.Generic;
 
class GFG
{
static int M = 18;
static int a, b;
static int [,,,]dp = new int[M, 90, 90, 2];
 
// Prime numbers upto 100
static int []prime = { 2, 3, 5, 7, 11, 13, 17, 19, 23,
                       29, 31, 37, 43, 47, 53, 59, 61,
                       67, 71, 73, 79, 83, 89, 97 };
 
// Function to return the count of
// required numbers from 0 to num
static int count(int pos, int even,
                 int odd, int tight,
                 List<int> num)
{
    // Base Case
    if (pos == num.Count)
    {
        if ((num.Count & 1) != 0)
        {
            int t = odd;
            odd = even;
            even = t;
             
        }
         
        int d = even - odd;
 
        // check if the difference is equal
        // to any prime number
        for (int i = 0; i < 24; i++)
            if (d == prime[i])
                return 1;
                 
        return 0;
    }
 
    // If this result is already computed
    // simply return it
    if (dp[pos, even, odd, tight] != -1)
        return dp[pos, even, odd, tight];
 
    int ans = 0;
 
    // Maximum limit upto which we can place
    // digit. If tight is 1, means number has
    // already become smaller so we can place
    // any digit, otherwise num[pos]
    int limit = (tight != 0 ? 9 : num[pos]);
 
    for (int d = 0; d <= limit; d++)
    {
        int currF = tight, currEven = even;
        int currOdd = odd;
         
        if (d < num[pos])
            currF = 1;
 
        // If the current position is odd
        // add it to currOdd, otherwise to
        // currEven
        if ((pos & 1) != 0)
            currOdd += d;
        else
            currEven += d;
             
        ans += count(pos + 1, currEven,
                     currOdd, currF, num);
    }
     
    return dp[pos, even, odd, tight] = ans;
}
 
// Function to convert x into its digit vector
// and uses count() function to return the
// required count
static int solve(int x)
{
    List<int> num = new List<int>();
     
    while (x != 0)
    {
        num.Add(x % 10);
        x /= 10;
    }
     
    num.Reverse();
 
    // Initialize dp
    for(int i = 0; i < dp.GetLength(0); i++)
        for(int j = 0; j < dp.GetLength(1); j++)
            for(int k = 0; k < dp.GetLength(2); k++)
                for(int k1 = 0; k1 < dp.GetLength(3); k1++)
                    dp[i, j, k, k1] = -1;
     
    return count(0, 0, 0, 0, num);
}
 
// Driver Code
public static void Main(String []args)
{
    int L = 1, R = 50;
    Console.WriteLine(solve(R) - solve(L - 1));
 
    L = 50; R = 100;
    Console.WriteLine(solve(R) - solve(L - 1));
}
}
 
// This code is contributed by Rajput-Ji




<script>
 
// JavaScript implementation of the above approach
var M = 18;
var a, b;
var dp = Array.from(Array(M), ()=>Array(90));
 
// Prime numbers upto 100
var prime = [2, 3, 5, 7, 11, 13, 17, 19, 23,
                29, 31, 37, 43, 47, 53, 59, 61,
                67, 71, 73, 79, 83, 89, 97 ];
 
// Function to return the count of
// required numbers from 0 to num
function count(pos, even, odd, tight, num)
{
    // Base Case
    if (pos == num.length) {
        if (num.length & 1)
            [odd, even] = [even, odd]
        var d = even - odd;
 
        // check if the difference is equal
        // to any prime number
        for (var i = 0; i < 24; i++)
            if (d == prime[i])
                return 1;
                 
        return 0;
    }
 
    // If this result is already computed
    // simply return it
    if (dp[pos][even][odd][tight] != -1)
        return dp[pos][even][odd][tight];
 
    var ans = 0;
 
    // Maximum limit upto which we can place
    // digit. If tight is 1, means number has
    // already become smaller so we can place
    // any digit, otherwise num[pos]
    var limit = (tight ? 9 : num[pos]);
 
    for (var d = 0; d <= limit; d++) {
        var currF = tight, currEven = even;
        var currOdd = odd;
         
        if (d < num[pos])
            currF = 1;
 
        // If the current position is odd
        // add it to currOdd, otherwise to
        // currEven
        if (pos & 1)
            currOdd += d;
        else
            currEven += d;
             
        ans += count(pos + 1, currEven, currOdd,
                    currF, num);
    }
     
    return dp[pos][even][odd][tight] = ans;
}
 
// Function to convert x into its digit vector
// and uses count() function to return the
// required count
function solve(x)
{
    var num = [];
     
    while (x) {
        num.push(x % 10);
        x = parseInt(x/10);
    }
     
    num.reverse();
 
    // Initialize dp
    for(var i =0; i<M; i++)
        for(var j =0; j<90; j++)
            dp[i][j] = Array.from(Array(90),  ()=>Array(2).fill(-1))
    return count(0, 0, 0, 0, num);
}
 
// Driver Code
var L = 1, R = 50;
document.write( solve(R) - solve(L - 1) + "<br>");
L = 50, R = 100;
document.write( solve(R) - solve(L - 1));
 
</script>

Output
6
18

Time Complexity: O(pos*limit)

Auxiliary Space: O(M*90*90*2)


Article Tags :