📌  相关文章
📜  被M整除并在奇数位具有D的范围内的数字计数

📅  最后修改于: 2021-04-24 05:17:39             🧑  作者: Mango

给定两个数字M,D和一个代表范围[L,R]的数组arr [] ,任务是计算范围[L,R]中的数字,这些数字可以被M整除,并且数字D在每个奇数处出现职位。

注意:数字可能很大。因此,范围数组{L,R}以字符串的形式给出。

例子:

幼稚的方法:针对此问题的幼稚的方法是取L到R之间的每个数字,并检查数字D是否出现在奇数位置,以及该数字是否可被M整除。此解决方案的时间复杂度为O(N * K),其中N是[L,R]范围内的数字计数,K是[L,R]范围内任何数字的最大位数。

高效的方法:想法是使用digit-dp的概念,并找到解决问题的数字组合的数量。为了找到满足条件的数目的计数,我们找到满足条件的数目的计数,直到该范围内的最高数目R。这包括所有1位,2位,3位数字。找到该计数后,我们只需从上述值中减去满足L – 1的数即可得到最终答案。

  1. 假设数字为数字序列,我们尝试形成一个N位数,该数字遵循每次迭代的条件,其中N是给定上限R中的位数。让计数为C。
  2. 此计数C包括1位数字,2位数字,3位数字…直至N位数字,其中N是R中的数字。
  3. 同样,我们找到满足L – 1条件的数。使该数为D。
  4. 所需的答案是两个计数C – D之差
  5. 满足给定条件的数字的计数是通过数字dp的概念找到的。
  6. 使用此概念可以形成并填充一个三维表。

下面是上述方法的实现:

C++14
// C++ program to find the count of numbers
// in the range [L, R] which are divisible
// by M and have digit D at the odd places
 
#include 
using namespace std;
#define ll long long int
 
// Variables to store M, N, D
ll m, n, d;
 
// Vector to store the digit number
// in the form of digits
vector v;
ll const k = 1e9 + 7;
 
// Dp table to compute the answer
ll dp[2001][2001][2];
 
// Function to add the individual
// digits into the vector
void init(string s)
{
    memset(dp, -1, sizeof(dp));
    v.clear();
 
    // Iterating through the number
    // and adding the digits into
    // the vector
    for (int i = 0; i < s.size(); i++) {
        v.push_back(s[i] - '0');
    }
    n = s.size();
}
 
// Function to subtract 1 from a number
// represented in a form of a string
string number_minus_one(string a)
{
    string s = a.substr(1);
    string s1 = "";
 
    // Iterating through the number
    for (int i = 0; i < s.size() - 1; i++)
        s1 += '0';
 
    // If the first digit is 1, then make it 0
    // and add 9 at the end of the string.
    if (a[0] == 1 and s == s1) {
        ll l = s.size();
        a = "";
        a += '0';
        for (int i = 0; i < l; i++)
            a += '9';
    }
    else {
        for (int i = a.size() - 1; i >= 0; i--) {
 
            // If we need to subtract 1 from 0,
            // then make it 9 and subtract 1
            // from the previous digits
            if (a[i] == '0')
                a[i] = '9';
 
            // Else, simply subtract 1
            else {
                a[i] = (((a[i] - '0') - 1) + '0');
                break;
            }
        }
    }
    return a;
}
 
// Function to find the count of numbers
// in the range [L, R] which are divisible
// by M and have digit D at the odd places
ll fun(ll pos, ll sum, ll f)
{
 
    // Base case
    if (pos == n) {
        if (sum == 0) {
 
            // If we have built N-digit number
            // and the number is divisible
            // by m then we have got
            // one possible answer.
            return 1;
        }
        return 0;
    }
 
    // If the answer has already been computed,
    // then return the answer
    if (dp[pos][sum][f] != -1)
        return dp[pos][sum][f];
    ll lmt = 9;
 
    // The possible digits which we can
    // place at the pos position.
    if (!f)
        lmt = v[pos];
 
    ll ans = 0;
 
    // Iterating through all the digits
    for (ll i = 0; i <= lmt; i++) {
        if (i == d and pos % 2 == 1)
            ans += 0;
        else if (i != d and pos % 2 == 0)
            ans += 0;
        else {
            ll new_f = f;
 
            // If we have placed all the digits
            // up to pos-1 equal to their
            // limit and currently we are placing
            // a digit which is smaller than this
            // position's limit then we can place
            // 0 to 9 at all the next positions
            // to make the number smaller than R
            if (f == 0 and i < lmt)
                new_f = 1;
 
            // Calculating the number upto pos mod m.
            ll new_sum = sum;
 
            // Combinations of numbers as there are
            // 10 digits in the range [0, 9]
            new_sum *= 10;
            new_sum += i;
            new_sum %= m;
 
            // Recursively call the function
            // for the next position
            ans += fun(pos + 1, new_sum, new_f);
            ans %= k;
        }
    }
 
    // Returning the final answer
    return dp[pos][sum][f] = ans;
}
 
// Function to call the function
// for every query
void operations(string L, string R)
{
    init(R);
    ll ans = fun(0, 0, 0);
    L = number_minus_one(L);
    init(L);
    ans -= fun(0, 0, 0);
    if (ans < 0)
        ans += k;
    cout << ans << "\n";
}
 
// Driver code
int main()
{
    m = 2, d = 2;
    ll Q = 1;
    string arr[][2] = { { "20", "32" } };
 
    for (ll i = 0; i < Q; i++) {
        operations(arr[i][0], arr[i][1]);
    }
 
    return 0;
}


Java
// Java program to find the count of numbers
// in the range [L, R] which are divisible
// by M and have digit D at the odd places
import java.util.ArrayList;
import java.util.Arrays;
 
class Graph{
 
// Variables to store M, N, D
static int m, n, d;
 
// Vector to store the digit number
// in the form of digits
static ArrayList v = new ArrayList<>();
static final int k = (int) 1e9 + 7;
 
// Dp table to compute the answer
static int[][][] dp = new int[2001][2001][2];
 
// Function to add the individual
// digits into the vector
static void init(StringBuilder l)
{
    for(int i = 0; i < 2001; i++)
    {
        for(int j = 0; j < 2001; j++)
        {
            for(int k = 0; k < 2; k++)
            {
                dp[i][j][k] = -1;
            }
        }
    }
    v.clear();
     
    // Iterating through the number
    // and adding the digits into
    // the vector
    for(int i = 0; i < l.length(); i++)
    {
        v.add(l.charAt(i) - '0');
    }
    n = l.length();
  
}
 
// Function to subtract 1 from a number
// represented in a form of a String
static String number_minus_one(StringBuilder a)
{
    String s = a.substring(1);
  
    String s1 = "";
     
    // Iterating through the number
    for(int i = 0; i < s.length() - 1; i++)
        s1 += '0';
         
    // If the first digit is 1, then make it 0
    // and add 9 at the end of the String.
    if (a.charAt(0) == '1' && s.compareTo(s1) == 0)
    {
        int l = s.length();
        a = new StringBuilder("");
        a.append('0');
         
        for(int i = 0; i < l; i++)
            a.append('9');
       
    }
    else
    {
        for(int i = a.length() - 1; i >= 0; i--)
        {
             
            // If we need to subtract 1 from 0,
            // then make it 9 and subtract 1
            // from the previous digits
            if (a.charAt(i) == '0')
                a.setCharAt(i, '9');
                 
            // Else, simply subtract 1
            else
            {
                a.setCharAt(i, (char)(
                    ((a.charAt(i) - '0') - 1) + '0'));
                break;
            }
         
        }
    }
 
    return a.toString();
}
 
// Function to find the count of numbers
// in the range [L, R] which are divisible
// by M and have digit D at the odd places
static int fun(int pos, int sum, int f)
{
     
    // Base case
    if (pos == n)
    {
        if (sum == 0)
        {
             
            // If we have built N-digit number
            // and the number is divisible
            // by m then we have got
            // one possible answer.
            return 1;
        }
        return 0;
    }
 
    // If the answer has already been computed,
    // then return the answer
    if (dp[pos][sum][f] != -1)
        return dp[pos][sum][f];
         
    int lmt = 9;
 
    // The possible digits which we can
    // place at the pos position.
    if (f == 0)
        lmt = v.get(pos);
 
    int ans = 0;
 
    // Iterating through all the digits
    for(int i = 0; i <= lmt; i++)
    {
        if (i == d && pos % 2 == 1)
            ans += 0;
        else if (i != d && pos % 2 == 0)
            ans += 0;
        else
        {
            int new_f = f;
             
            // If we have placed all the digits
            // up to pos-1 equal to their
            // limit and currently we are placing
            // a digit which is smaller than this
            // position's limit then we can place
            // 0 to 9 at all the next positions
            // to make the number smaller than R
            if (f == 0 && i < lmt)
                new_f = 1;
 
            // Calculating the number upto pos mod m.
            int new_sum = sum;
 
            // Combinations of numbers as there are
            // 10 digits in the range [0, 9]
            new_sum *= 10;
            new_sum += i;
            new_sum %= m;
 
            // Recursively call the function
            // for the next position
            ans += fun(pos + 1, new_sum, new_f);
            ans %= k;
        }
    }
 
    // Returning the final answer
    return dp[pos][sum][f] = ans;
}
 
// Function to call the function
// for every query
static void operations(StringBuilder L,
                       StringBuilder R)
{
    init(R);
    int ans = fun(0, 0, 0);
    L = new StringBuilder(number_minus_one(L));
    init(L);
    ans -= fun(0, 0, 0);
     
    if (ans < 0)
        ans += k;
         
    System.out.println(ans);
}
 
// Driver code
public static void main(String[] args)
{
    m = 2;
    d = 2;
    int Q = 1;
     
    StringBuilder[][] arr = {
        { new StringBuilder("20"),
          new StringBuilder("32") } };
     
    for(int i = 0; i < Q; i++)
    {
        operations(arr[i][0], arr[i][1]);
    }
}
}
 
// This code is contributed by sanjeev2552


C#
// C# program to find the count of numbers
// in the range [L, R] which are divisible
// by M and have digit D at the odd places
using System;
using System.Collections.Generic;
class Graph{
 
// Variables to store M, N, D
static int m, n, d;
 
// Vector to store the digit number
// in the form of digits
static List v = new List();
static int k = (int) 1e9 + 7;
 
// Dp table to compute the answer
static int[,,] dp = new int[2001, 2001, 2];
 
// Function to add the individual
// digits into the vector
static void init(string l)
{
    for(int i = 0; i < 2001; i++)
    {
        for(int j = 0; j < 2001; j++)
        {
            for(int k = 0; k < 2; k++)
            {
                dp[i, j, k] = -1;
            }
        }
    }
    v.Clear();
     
    // Iterating through the number
    // and adding the digits into
    // the vector
    for(int i = 0; i < l.Length; i++)
    {
        v.Add(l[i] - '0');
    }
    n = l.Length;
   
}
 
// Function to subtract 1 from a number
// represented in a form of a String
static string number_minus_one(string a)
{
    string s = a.Substring(1);
    string s1 = "";
     
    // Iterating through the number
    for(int i = 0; i < s.Length - 1; i++)
        s1 += '0';
 
    // If the first digit is 1, then make it 0
    // and add 9 at the end of the String.
    if (a[0] == '1' && String.Compare(s, s1) == 0)
    {
        int l = s.Length;     
        a = a.Replace(a[0], '0');       
        for(int i = 0; i < l; i++)
            a+='9';
    }
    else
    {
        for(int i = a.Length - 1; i >= 0; i--)
        {
             
            // If we need to subtract 1 from 0,
            // then make it 9 and subtract 1
            // from the previous digits
            if (a[i] == '0')
                a = a.Replace(a[i], '9');
                 
            // Else, simply subtract 1
            else
            {
                a = a.Replace(a[i], (char)(((a[i] - '0') - 1) + '0'));
                break;
            }     
        }
    }
    return a.ToString();
}
 
// Function to find the count of numbers
// in the range [L, R] which are divisible
// by M and have digit D at the odd places
static int fun(int pos, int sum, int f)
{
     
    // Base case
    if (pos == n)
    {
        if (sum == 0)
        {
             
            // If we have built N-digit number
            // and the number is divisible
            // by m then we have got
            // one possible answer.
            return 1;
        }
        return 0;
    }
 
    // If the answer has already been computed,
    // then return the answer
    if (dp[pos, sum, f] != -1)
        return dp[pos, sum, f];      
    int lmt = 9;
 
    // The possible digits which we can
    // place at the pos position.
    if (f == 0)
        lmt = v[pos];
    int ans = 0;
 
    // Iterating through all the digits
    for(int i = 0; i <= lmt; i++)
    {
        if (i == d && pos % 2 == 1)
            ans += 0;
        else if (i != d && pos % 2 == 0)
            ans += 0;
        else
        {
            int new_f = f;
             
            // If we have placed all the digits
            // up to pos-1 equal to their
            // limit and currently we are placing
            // a digit which is smaller than this
            // position's limit then we can place
            // 0 to 9 at all the next positions
            // to make the number smaller than R
            if (f == 0 && i < lmt)
                new_f = 1;
 
            // Calculating the number upto pos mod m.
            int new_sum = sum;
 
            // Combinations of numbers as there are
            // 10 digits in the range [0, 9]
            new_sum *= 10;
            new_sum += i;
            new_sum %= m;
 
            // Recursively call the function
            // for the next position
            ans += fun(pos + 1, new_sum, new_f);
            ans %= k;
        }
    }
 
    // Returning the final answer
    dp[pos, sum, f] = ans;
  return dp[pos, sum, f];
}
 
// Function to call the function
// for every query
static void operations(string L, string R)
{
    init(R);
    int ans = fun(0, 0, 0);
    L = number_minus_one(L);
    init(L);
    ans -= fun(0, 0, 0);
     
    if (ans < 0)
        ans += k;
         
    Console.WriteLine(ans);
}
 
// Driver code
public static void Main(String[] args)
{
    m = 2;
    d = 2;
    int Q = 1;   
    string[,] arr = { {"20",
          "32"  }}; 
    for(int i = 0; i < Q; i++)
    {
        operations(arr[i, 0], arr[i, 1]);
    }
}
}
 
// This code is contributed by chitranayal


输出:
4