给定两个数字M, D和一个表示范围[L, R]的数组arr[] ,任务是计算可被M整除的范围[L, R]中的数字,数字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
Javascript
4
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。