📌  相关文章
📜  范围内的数字计数,该范围可被m整除并且在偶数位置具有d

📅  最后修改于: 2021-06-25 14:00:07             🧑  作者: Mango

给定一个范围,该范围由两个正整数lr以及两个整数dm表示。查找位于可以被m整除并且在偶数位置具有数字d的范围内的数字计数。 (即,数字d不应出现在奇数位置)。注意:数字l和r具有相同的数字位数。

先决条件: Digit DP

方法:首先,如果我们能够计算所需的数字,直到R,即在[0,R]范围内,则可以通过求解从零到R的值,然后减去,可以很容易地在[L,R]范围内得出答案。从零到L – 1求解后得到的答案。现在,我们需要定义DP状态。
DP州:

  • 由于我们可以将数字视为数字序列,因此一个状态是我们当前所处的位置。如果要处理的数字最大为1018,则该位置的值可以为0到18。在每个递归调用中,我们尝试通过从0到9放置一个数字从左到右构建序列。
  • 第二种状态是余数,它定义了到目前为止我们对模取m的模数。
  • 另一个状态是布尔变量tight,它指示我们要构建的数字已经小于R,因此在接下来的递归调用中,我们可以将0到9之间的任何数字放置。如果数字没有变小,则为最大限制我们可以放置的位数是R中当前位置的位数。

如果当前位置是偶数位置,我们只需放置数字d并递归求解下一个位置。但是,如果当前位置是一个奇数位置,我们可以放置除d之外的任何数字,然后求解下一个位置。

下面是上述方法的实现。

C++
// CPP Program to find the count of
// numbers in a range divisible by m
// having digit d at even positions
#include 
using namespace std;
  
const int M = 20;
  
// states - position, rem, tight
int dp[M][M][2];
  
// d is required digit and number should
// be divisible by m
int d, m;
  
// This function returns the count of
// required numbers from 0 to num
int count(int pos, int rem, int tight,
          vector num)
{
    // Last position
    if (pos == num.size()) {
        if (rem == 0)
            return 1;
        return 0;
    }
  
    // If this result is already computed
    // simply return it
    if (dp[pos][rem][tight] != -1)
        return dp[pos][rem][tight];
  
    // If the current position is even, place
    // digit d, but since we have considered
    // 0-indexing, check for odd positions
    if (pos % 2) {
        if (tight == 0 && d > num[pos])
            return 0;
  
        int currTight = tight;
  
        // At this position, number becomes
        // smaller
        if (d < num[pos])
            currTight = 1;
  
        int res = count(pos + 1, (10 * rem + d)
                                     % m,
                        currTight, num);
        return dp[pos][rem][tight] = res;
    }
  
    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 dig = 0; dig <= limit; dig++) {
  
        if (dig == d)
            continue;
  
        int currTight = tight;
  
        // At this position, number becomes
        // smaller
        if (dig < num[pos])
            currTight = 1;
  
        // Next recursive call, also set nonz
        // to 1 if current digit is non zero
        ans += count(pos + 1, (10 * rem + dig)
                                  % m,
                     currTight, num);
    }
    return dp[pos][rem][tight] = ans;
}
  
// Function to convert x into its digit vector
// and uses count() function to return the
// required count
int solve(int x)
{
    vector 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, num);
}
  
// Driver Code to test above functions
int main()
{
    int L = 10, R = 99;
    d = 8, m = 2;
    cout << solve(R) - solve(L) << endl;
  
    return 0;
}


Java
// Java Program to find the count of 
// numbers in a range divisible by m 
// having digit d at even positions
  
import java.util.*;
  
class GFG 
{
  
    static int M = 20;
  
    // states - position, rem, tight
    static Integer[][][] dp = new Integer[M][M][2];
  
    // d is required digit and number should
    // be divisible by m
    static int d, m;
  
    // This function returns the count of
    // required numbers from 0 to num
    static int count(int pos, int rem, int tight,
                            Vector num)
    {
  
        // Last position
        if (pos == num.size()) 
        {
            if (rem == 0)
                return 1;
            return 0;
        }
  
        // If this result is already computed
        // simply return it
        if (dp[pos][rem][tight] != -1)
            return dp[pos][rem][tight];
  
        // If the current position is even, place
        // digit d, but since we have considered
        // 0-indexing, check for odd positions
        if (pos % 2 == 1)
        {
            if (tight == 0 && d > num.elementAt(pos))
                return 0;
  
            int currTight = tight;
  
            // At this position, number becomes
            // smaller
            if (d < num.elementAt(pos))
                currTight = 1;
  
            int res = count(pos + 1, (10 * rem + d) % m,
                                        currTight, num);
            return dp[pos][rem][tight] = res;
        }
  
        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.elementAt(pos);
        for (int dig = 0; dig <= limit; dig++) 
        {
  
            if (dig == d)
                continue;
  
            int currTight = tight;
  
            // At this position, number becomes
            // smaller
            if (dig < num.elementAt(pos))
                currTight = 1;
  
            // Next recursive call, also set nonz
            // to 1 if current digit is non zero
            ans += count(pos + 1, (10 * rem + dig) % m,
                                        currTight, num);
        }
        return dp[pos][rem][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 num = new Vector<>();
        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++)
                    dp[i][j][k] = -1;
  
        return count(0, 0, 0, num);
    }
  
    // Driver Code
    public static void main(String[] args)
    {
        int L = 10, R = 99;
        d = 8;
        m = 2;
        System.out.println(solve(R) - solve(L));
    }
}
  
// This code is contributed by
// sanjeev2552


Python3
# Python3 Program to find the count of 
# numbers in a range divisible by m 
# having digit d at even positions 
  
# This Function returns the count of 
# required numbers from 0 to num 
def count(pos, rem, tight, num): 
  
    # Last position 
    if pos == len(num): 
        if rem == 0: 
            return 1
        return 0
      
    # If this result is already
    # computed simply return it 
    if dp[pos][rem][tight] != -1: 
        return dp[pos][rem][tight] 
  
    # If the current position is even, 
    # place digit d, but since we have 
    # considered 0-indexing, check for 
    # odd positions 
    if pos % 2 == 1:
        if tight == 0 and d > num[pos]: 
            return 0
  
        currTight = tight 
  
        # At this position, number 
        # becomes smaller 
        if d < num[pos]: 
            currTight = 1
  
        res = count(pos + 1, (10 * rem + d) % m, 
                                 currTight, num)
          
        dp[pos][rem][tight] = res         
        return res
      
    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 dig in range(0, limit + 1): 
        if dig == d:
            continue
  
        currTight = tight 
  
        # At this position, number becomes 
        # smaller 
        if dig < num[pos]: 
            currTight = 1
  
        # Next recursive call, also set nonz 
        # to 1 if current digit is non zero 
        ans += count(pos + 1, (10 * rem + dig) % m, 
                                    currTight, num) 
      
    dp[pos][rem][tight] = ans
    return ans
      
# 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 > 0: 
        num.append(x % 10) 
        x = x // 10
      
    num.reverse() 
    # Initialize dp with -1
    dp = [[[-1, -1] for x in range(M)] 
                    for y in range(M)]
      
    return count(0, 0, 0, num) 
  
# Driver Code
if __name__ == "__main__":
  
    L, R = 10, 99
      
    # d is required digit and number
    # should be divisible by m 
    d, m = 8, 2
    M = 20
      
    # states - position, rem, tight
    dp = []
    print(solve(R) - solve(L))
  
# This code is contributed 
# by Rituraj Jain


C#
// C# Program to find the count of 
// numbers in a range divisible by m 
// having digit d at even positions
using System;
using System.Collections.Generic;
  
class GFG 
{
  
    static int M = 20;
  
    // states - position, rem, tight
    static int[,,] dp = new int[M, M, 2];
  
    // d is required digit and number should
    // be divisible by m
    static int d, m;
  
    // This function returns the count of
    // required numbers from 0 to num
    static int count(int pos, int rem, int tight,
                            List num)
    {
  
        // Last position
        if (pos == num.Count) 
        {
            if (rem == 0)
                return 1;
            return 0;
        }
  
        // If this result is already computed
        // simply return it
        if (dp[pos, rem, tight] != -1)
            return dp[pos, rem, tight];
  
        // If the current position is even, place
        // digit d, but since we have considered
        // 0-indexing, check for odd positions
        if (pos % 2 == 1)
        {
            if (tight == 0 && d > num[pos])
                return 0;
  
            int currTight = tight;
  
            // At this position, number becomes
            // smaller
            if (d < num[pos])
                currTight = 1;
  
            int res = count(pos + 1, (10 * rem + d) % m,
                                        currTight, num);
            return dp[pos, rem, tight] = res;
        }
  
        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 dig = 0; dig <= limit; dig++) 
        {
  
            if (dig == d)
                continue;
  
            int currTight = tight;
  
            // At this position, number becomes
            // smaller
            if (dig < num[pos])
                currTight = 1;
  
            // Next recursive call, also set nonz
            // to 1 if current digit is non zero
            ans += count(pos + 1, (10 * rem + dig) % m,
                                        currTight, num);
        }
        return dp[pos, rem, 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 num = new List();
        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++)
                    dp[i, j, k] = -1;
  
        return count(0, 0, 0, num);
    }
  
    // Driver Code
    public static void Main(String[] args)
    {
        int L = 10, R = 99;
        d = 8;
        m = 2;
        Console.WriteLine(solve(R) - solve(L));
    }
}
  
// This code is contributed by Rajput-Ji


PHP
 $num[$pos]) 
            return 0; 
  
        $currTight = $tight; 
  
        // At this position, number becomes 
        // smaller 
        if ($GLOBALS['d'] < $num[$pos]) 
            $currTight = 1; 
  
        $res = count_num($pos + 1, (10 * $rem + 
                         $GLOBALS['d']) % $GLOBALS['m'], 
                         $currTight, $num); 
        return $dp[$pos][$rem][$tight] = $res; 
    } 
  
    $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 = ($tight ? 9 : $num[$pos]); 
  
    for ($dig = 0; $dig <= $limit; $dig++)
    { 
  
        if ($dig == $GLOBALS['d']) 
            continue; 
  
        $currTight = $tight; 
  
        // At this position, number becomes 
        // smaller 
        if ($dig < $num[$pos]) 
            $currTight = 1; 
  
        // Next recursive call, also set nonz 
        // to 1 if current digit is non zero 
        $ans += count_num($pos + 1, (10 * $rem + $dig) % 
                          $GLOBALS['m'], $currTight, $num); 
    } 
    return $dp[$pos][$rem][$tight] = $ans; 
} 
  
// Function to convert x into its digit 
// vector and uses count() function to 
// return the required count 
function solve($x) 
{ 
    $num = array() ;
    while ($x) 
    { 
        array_push($num, $x % 10); 
        $x = floor($x / 10); 
    } 
    $num = array_reverse($num) ;
  
    // Initialize dp 
    for($i = 0 ; $i < $GLOBALS['M'] ; $i++)
        for($j = 0; $j < $GLOBALS['M']; $j++)
            for($k = 0; $k < 2; $k ++)
                $GLOBALS['dp'][$i][$j][$k] = -1;
              
    return count_num(0, 0, 0, $num); 
} 
  
// Driver Code
$GLOBALS['M'] = 20; 
  
// states - position, rem, tight 
$GLOBALS['dp'] = array(array(array()));
  
$L = 10;
$R = 99; 
  
// d is required digit and number 
// should be divisible by m 
$GLOBALS['d'] = 8 ;
$GLOBALS['m'] = 2; 
  
echo solve($R) - solve($L) ; 
  
// This code is contributed by Ryuga
?>


输出:

8

时间复杂度: O(18 *(m – 1)* 2),如果我们要处理的数字最大为10 18

如果您希望与行业专家一起参加现场课程,请参阅《 Geeks现场课程》和《 Geeks现场课程美国》。