给定两个数字M,D和一个代表范围[L,R]的数组arr [] ,任务是计算范围[L,R]中的数字,这些数字可以被M整除,并且数字D在每个奇数处出现职位。
注意:数字可能很大。因此,范围数组{L,R}以字符串的形式给出。
例子:
Input: arr[] = {20, 32}, M = 2, D = 2
Output: 4
Explanation:
There are 4 numbers in the range [20, 32] which are divisible by 2 and 2 at the odd (first) position. They are:
20, 24, 26, 28.
Input: arr[] = {40, 60}, M = 2, D = 5
Output: 5
Explanation:
There are 5 numbers in the range [40, 60] which are divisible by 2 and 5 at the odd (first) position. They are:
50, 52, 54, 56, 58.
幼稚的方法:针对此问题的幼稚的方法是取L到R之间的每个数字,并检查数字D是否出现在奇数位置,以及该数字是否可被M整除。此解决方案的时间复杂度为O(N * K),其中N是[L,R]范围内的数字计数,K是[L,R]范围内任何数字的最大位数。
高效的方法:想法是使用digit-dp的概念,并找到解决问题的数字组合的数量。为了找到满足条件的数目的计数,我们找到满足条件的数目的计数,直到该范围内的最高数目R。这包括所有1位,2位,3位数字。找到该计数后,我们只需从上述值中减去满足L – 1的数即可得到最终答案。
- 假设数字为数字序列,我们尝试形成一个N位数,该数字遵循每次迭代的条件,其中N是给定上限R中的位数。让计数为C。
- 此计数C包括1位数字,2位数字,3位数字…直至N位数字,其中N是R中的数字。
- 同样,我们找到满足L – 1条件的数。使该数为D。
- 所需的答案是两个计数C – D之差。
- 满足给定条件的数字的计数是通过数字dp的概念找到的。
- 使用此概念可以形成并填充一个三维表。
下面是上述方法的实现:
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