📌  相关文章
📜  仅具有非零数字且其位数之和为N且数字可被M整除的范围之间的数字计数

📅  最后修改于: 2021-04-22 03:39:23             🧑  作者: Mango

给定一个范围[L,R]以及两个正整数NM。任务是对仅包含非零数字范围内的数字进行计数,这些数字的总和等于N且该数字可被M整除

例子:

先决条件: Digit DP

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

  • 既然我们可以考虑我们的号码作为数字序列,一个状态是,我们目前的位置,这个位置可以有值从0到18,如果我们用数字处理高达10 18。在每个递归调用中,我们尝试通过从0到9放置一个数字来从左到右构建序列。
  • 第二个状态是到目前为止我们放置的数字的总和
  • 第三个状态是余数,它定义了到目前为止我们取模M的模数。
  • 另一个状态是布尔变量tight ,它指示我们要构建的数字已经小于R,因此在接下来的递归调用中,我们可以将0到9之间的任何数字放置。如果数字没有变小,则为最大限制我们可以放置的位数是R中当前位置的位数。

对于仅具有非零数字的数字,我们维护一个变量nonz ,如果1告诉我们放置的数字中的第一个数字为非零数字,其值将为nz ,因此,现在我们不能在即将到来的数字中放置任何零数字电话。否则,我们可以将零数字放在前导零处,以使当前数字中的数字数小于上限数。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
  
const int M = 20;
  
// states - position, sum, rem, tight
// sum can have values upto 162, if we
// are dealing with numbers upto 10^18
// when all 18 digits are 9, then sum
// is 18 * 9 = 162
int dp[M][165][M][2];
  
// n is the sum of digits and number should
// be divisible by m
int n, m;
  
// Function to return the count of
// required numbers from 0 to num
int count(int pos, int sum, int rem, int tight,
          int nonz, vector num)
{
    // Last position
    if (pos == num.size()) {
        if (rem == 0 && sum == n)
            return 1;
        return 0;
    }
  
    // If this result is already computed
    // simply return it
    if (dp[pos][sum][rem][tight] != -1)
        return dp[pos][sum][rem][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++) {
  
        // If the current digit is zero
        // and nonz is 1, we can't place it
        if (d == 0 && nonz)
            continue;
        int currSum = sum + d;
        int currRem = (rem * 10 + d) % m;
        int currF = tight || (d < num[pos]);
        ans += count(pos + 1, currSum, currRem,
                     currF, nonz || d, num);
    }
    return dp[pos][sum][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, 0, 0, num);
}
  
// Driver code
int main()
{
    int L = 1, R = 100;
    n = 8, m = 2;
    cout << solve(R) - solve(L);
    return 0;
}


Java
// Java implementation of the approach 
import java.util.*;
  
class GFG
{
      
static int M = 20; 
  
// states - position, sum, rem, tight 
// sum can have values upto 162, if we 
// are dealing with numbers upto 10^18 
// when all 18 digits are 9, then sum 
// is 18 * 9 = 162 
static int dp[][][][] = new int [M][165][M][2]; 
  
// n is the sum of digits and number should 
// be divisible by m 
static int n, m; 
  
// Function to return the count of 
// required numbers from 0 to num 
static int count(int pos, int sum, int rem, int tight, 
        int nonz, Vector num) 
{ 
    // Last position 
    if (pos == num.size())
    { 
        if (rem == 0 && sum == n) 
            return 1; 
        return 0; 
    } 
  
    // If this result is already computed 
    // simply return it 
    if (dp[pos][sum][rem][tight] != -1) 
        return dp[pos][sum][rem][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++)
    { 
  
        // If the current digit is zero 
        // and nonz is 1, we can't place it 
        if (d == 0 && nonz != 0) 
            continue; 
        int currSum = sum + d; 
        int currRem = (rem * 10 + d) % m; 
        int currF = (tight != 0 || (d < num.get(pos))) ? 1 : 0; 
        ans += count(pos + 1, currSum, currRem, 
                    currF, (nonz != 0 || d != 0) ? 1 : 0, num); 
    } 
    return dp[pos][sum][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 < M; i++)
        for(int j = 0; j < 165; j++)
            for(int k = 0; k < M; k++)
                for(int l = 0; l < 2; l++)
                    dp[i][j][k][l]=-1;
      
    return count(0, 0, 0, 0, 0, num); 
} 
  
// Driver code 
public static void main(String args[]) 
{ 
    int L = 1, R = 100; 
    n = 8; m = 2; 
    System.out.print( solve(R) - solve(L)); 
} 
}
  
// This code is contributed by Arnab Kundu


Python3
# Python3 implementation of the approach 
  
# Function to return the count of 
# required numbers from 0 to num 
def count(pos, Sum, rem, tight, nonz, num): 
  
    # Last position 
    if pos == len(num): 
        if rem == 0 and Sum == n: 
            return 1
        return 0
  
    # If this result is already computed 
    # simply return it
    if dp[pos][Sum][rem][tight] != -1: 
        return dp[pos][Sum][rem][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]
    if tight:
        limit = 9
    else: 
        limit = num[pos]
      
    for d in range(0, limit + 1): 
  
        # If the current digit is zero 
        # and nonz is 1, we can't place it 
        if d == 0 and nonz:
            continue
              
        currSum = Sum + d 
        currRem = (rem * 10 + d) % m 
        currF = int(tight or (d < num[pos])) 
        ans += count(pos + 1, currSum, currRem, 
                     currF, nonz or d, num) 
      
    dp[pos][Sum][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): 
  
    num = []
    global dp
      
    while x > 0: 
        num.append(x % 10) 
        x //= 10
      
    num.reverse() 
  
    # Initialize dp 
    dp = [[[[-1, -1] for i in range(M)] 
                     for j in range(165)] 
                     for k in range(M)]
    return count(0, 0, 0, 0, 0, num) 
  
# Driver code 
if __name__ == "__main__":
  
    L, R = 1, 100
      
    # n is the sum of digits and number 
    # should be divisible by m
    n, m, M = 8, 2, 20
      
    # States - position, sum, rem, tight 
    # sum can have values upto 162, if we 
    # are dealing with numbers upto 10^18 
    # when all 18 digits are 9, then sum 
    # is 18 * 9 = 162 
    dp = []
  
    print(solve(R) - solve(L)) 
      
# This code is contributed by Rituraj Jain


C#
// C# implementation of the approach 
using System;
using System.Collections.Generic;
  
class GFG
{
      
static int M = 20; 
  
// states - position, sum, rem, tight 
// sum can have values upto 162, if we 
// are dealing with numbers upto 10^18 
// when all 18 digits are 9, then sum 
// is 18 * 9 = 162 
static int [,,,]dp = new int [M, 165, M, 2]; 
  
// n is the sum of digits and number should 
// be divisible by m 
static int n, m; 
  
// Function to return the count of 
// required numbers from 0 to num 
static int count(int pos, int sum, int rem, int tight, 
                            int nonz, List num) 
{ 
    // Last position 
    if (pos == num.Count)
    { 
        if (rem == 0 && sum == n) 
            return 1; 
        return 0; 
    } 
  
    // If this result is already computed 
    // simply return it 
    if (dp[pos,sum,rem,tight] != -1) 
        return dp[pos,sum,rem,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++)
    { 
  
        // If the current digit is zero 
        // and nonz is 1, we can't place it 
        if (d == 0 && nonz != 0) 
            continue; 
        int currSum = sum + d; 
        int currRem = (rem * 10 + d) % m; 
        int currF = (tight != 0 || (d < num[pos])) ? 1 : 0; 
        ans += count(pos + 1, currSum, currRem, 
                    currF, (nonz != 0 || d != 0) ? 1 : 0, num); 
    } 
    return dp[pos, sum, 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 < M; i++)
        for(int j = 0; j < 165; j++)
            for(int k = 0; k < M; k++)
                for(int l = 0; l < 2; l++)
                    dp[i, j, k, l] = -1;
      
    return count(0, 0, 0, 0, 0, num); 
} 
  
// Driver code 
public static void Main(String []args) 
{ 
    int L = 1, R = 100; 
    n = 8; m = 2; 
    Console.Write( solve(R) - solve(L)); 
} 
}
  
// This code has been contributed by 29AjayKumar


Python3
# User Input
l, r, n, m = 1, 100, 8, 2
  
# Initialize Result
output = []
  
# Traverse through all numbers
for x in range(l, r+1):
  
    # Check for all conditions in every number 
    if sum([int(k) for k in str(x)]) == n and x % m == 0 and '0' not in str(x): # Check conditions
        output.append(x)
   
print(len(output))  
   
# This code is contributed by mailprakashindia


输出:
4


简短的Python实现:

Python3

# User Input
l, r, n, m = 1, 100, 8, 2
  
# Initialize Result
output = []
  
# Traverse through all numbers
for x in range(l, r+1):
  
    # Check for all conditions in every number 
    if sum([int(k) for k in str(x)]) == n and x % m == 0 and '0' not in str(x): # Check conditions
        output.append(x)
   
print(len(output))  
   
# This code is contributed by mailprakashindia