给定两个整数L和R,它们表示范围[L,R]。任务是找到给定范围[L,R]中的数字总数,该数字的偶数位数之和大于奇数位数之和。
例子:
Input : L=2 R=10
Output : 4
Numbers having the property that sum of even
digits is greater than sum of odd digits are: 2, 4, 6, 8
Input : L=2 R=17
Output : 7
先决条件: Digit-DP
方法:
首先,对所需的数字进行计数,直到R为止,即[0,R]范围内。要获得[L,R]范围内的答案,请求解从零到R的范围,然后减去从零到L – 1范围的答案。按如下所示定义DP状态:
- 将数字视为一个数字序列,一个状态是我们当前所处的位置。如果我们处理的数字最大为10 ^ 18,则此位置的值可以为0到18。在每个递归调用中,尝试通过从0到9放置一个数字从左到右构建序列。
- 第一个状态是到目前为止已放置的偶数位的总和。
- 第二状态是到目前为止已放置的奇数位数的总和。
- 另一个状态是布尔变量tight ,它指示我们要构建的数字已经小于R,因此在接下来的递归调用中,我们可以将0到9之间的任何数字放置。如果数字没有变小,则为最大限制我们可以放置的位数是R中当前位置的位数。
下面是上述方法的实现:
C++
// C++ code to count number in the range
// having the sum of even digits greater
// than the sum of odd digits
#include
// as the number can be up to 10^18
#define int long long
using namespace std;
vector v;
int dp[18][180][180][2];
int memo(int index, int evenSum,
int oddSum, int tight)
{
// Base Case
if (index == v.size()) {
// check if condition satisfied or not
if (evenSum > oddSum)
return 1;
else
return 0;
}
// If this result is already computed
// simply return it
if (dp[index][evenSum][oddSum][tight] != -1)
return dp[index][evenSum][oddSum][tight];
// Maximum limit upto which we can place
// digit. If tight is 0, means number has
// already become smaller so we can place
// any digit, otherwise num[pos]
int limit = (tight) ? v[index] : 9;
int ans = 0;
for (int d = 0; d <= limit; d++) {
int currTight = 0;
if (d == v[index])
currTight = tight;
// if current digit is odd
if (d % 2 != 0)
ans += memo(index + 1, evenSum,
oddSum + d, currTight);
// if current digit is even
else
ans += memo(index + 1, evenSum + d,
oddSum, currTight);
}
dp[index][evenSum][oddSum][tight] = ans;
return ans;
}
// Function to convert n into its
// digit vector and uses memo() function
// to return the required count
int CountNum(int n)
{
v.clear();
while (n) {
v.push_back(n % 10);
n = n / 10;
}
reverse(v.begin(), v.end());
// Initialize DP
memset(dp, -1, sizeof(dp));
return memo(0, 0, 0, 1);
}
// Driver Code
int32_t main()
{
int L, R;
L = 2;
R = 10;
cout << CountNum(R) - CountNum(L - 1) << "\n";
return 0;
}
Java
// Java code to count number in the range
// having the sum of even digits greater
// than the sum of odd digits
import java.util.*;
class GFG
{
static Vector v = new Vector<>();
static int[][][][] dp = new int[18][180][180][2];
static int memo(int index, int evenSum,
int oddSum, int tight)
{
// Base Case
if (index == v.size())
{
// check if condition satisfied or not
if (evenSum > oddSum)
{
return 1;
}
else
{
return 0;
}
}
// If this result is already computed
// simply return it
if (dp[index][evenSum][oddSum][tight] != -1)
{
return dp[index][evenSum][oddSum][tight];
}
// Maximum limit upto which we can place
// digit. If tight is 0, means number has
// already become smaller so we can place
// any digit, otherwise num[pos]
int limit = (tight > 0) ? v.get(index) : 9;
int ans = 0;
for (int d = 0; d <= limit; d++)
{
int currTight = 0;
if (d == v.get(index))
{
currTight = tight;
}
// if current digit is odd
if (d % 2 != 0)
{
ans += memo(index + 1, evenSum,
oddSum + d, currTight);
} // if current digit is even
else
{
ans += memo(index + 1, evenSum + d,
oddSum, currTight);
}
}
dp[index][evenSum][oddSum][tight] = ans;
return ans;
}
// Function to convert n into its
// digit vector and uses memo() function
// to return the required count
static int CountNum(int n)
{
v.clear();
while (n > 0)
{
v.add(n % 10);
n = n / 10;
}
Collections.reverse(v);
// Initialize DP
for (int i = 0; i < 18; i++)
{
for (int j = 0; j < 180; j++)
{
for (int k = 0; k < 180; k++)
{
for (int l = 0; l < 2; l++)
{
dp[i][j][k][l] = -1;
}
}
}
}
return memo(0, 0, 0, 1);
}
// Driver Code
public static void main(String[] args)
{
int L, R;
L = 2;
R = 10;
System.out.println(CountNum(R) - CountNum(L - 1));
}
}
// This code is contributed by Princi Singh
Python3
# Python code to count number in the range
# having the sum of even digits greater
# than the sum of odd digits
def memo(index, evenSum, oddSum, tight):
# Base Case
if index == len(v):
# check if condition satisfied or not
if evenSum > oddSum:
return 1
else:
return 0
# If this result is already computed
# simply return it
if dp[index][evenSum][oddSum][tight] != -1:
return dp[index][evenSum][oddSum][tight]
# Maximum limit upto which we can place
# digit. If tight is 0, means number has
# already become smaller so we can place
# any digit, otherwise num[index]
limit = v[index] if tight else 9
ans = 0
for d in range(limit + 1):
currTight = 0
if d == v[index]:
currTight = tight
# if current digit is odd
if d % 2 != 0:
ans += memo(index + 1, evenSum,
oddSum + d, currTight)
# if current digit is even
else:
ans += memo(index + 1, evenSum + d,
oddSum, currTight)
dp[index][evenSum][oddSum][tight] = ans
return ans
# Function to convert n into its digit vector
# and uses memo() function to return the
# required count
def countNum(n):
global dp, v
v.clear()
num = []
while n:
v.append(n % 10)
n //= 10
v.reverse()
# Initialize dp
dp = [[[[-1, -1] for i in range(180)] for j in range(180)]
for k in range(18)]
return memo(0, 0, 0, 1)
# Driver Code
if __name__ == "__main__":
dp = []
v = []
L = 2
R = 10
print(countNum(R) - countNum(L - 1))
# This code is contributed by
# sanjeev2552
C#
// C# code to count number in the range
// having the sum of even digits greater
// than the sum of odd digits
using System.Collections.Generic;
using System;
class GFG
{
static List v = new List();
static int [,,,]dp = new int[18,180,180,2];
static int memo(int index, int evenSum,
int oddSum, int tight)
{
// Base Case
if (index == v.Count)
{
// check if condition satisfied or not
if (evenSum > oddSum)
{
return 1;
}
else
{
return 0;
}
}
// If this result is already computed
// simply return it
if (dp[index,evenSum,oddSum,tight] != -1)
{
return dp[index,evenSum,oddSum,tight];
}
// Maximum limit upto which we can place
// digit. If tight is 0, means number has
// already become smaller so we can place
// any digit, otherwise num[pos]
int limit = (tight > 0) ? v[index] : 9;
int ans = 0;
for (int d = 0; d <= limit; d++)
{
int currTight = 0;
if (d == v[index])
{
currTight = tight;
}
// if current digit is odd
if (d % 2 != 0)
{
ans += memo(index + 1, evenSum,
oddSum + d, currTight);
} // if current digit is even
else
{
ans += memo(index + 1, evenSum + d,
oddSum, currTight);
}
}
dp[index,evenSum,oddSum,tight] = ans;
return ans;
}
// Function to convert n into its
// digit vector and uses memo() function
// to return the required count
static int CountNum(int n)
{
v.Clear();
while (n > 0)
{
v.Add(n % 10);
n = n / 10;
}
v.Reverse();
// Initialize DP
for (int i = 0; i < 18; i++)
{
for (int j = 0; j < 180; j++)
{
for (int k = 0; k < 180; k++)
{
for (int l = 0; l < 2; l++)
{
dp[i,j,k,l] = -1;
}
}
}
}
return memo(0, 0, 0, 1);
}
// Driver Code
public static void Main(String[] args)
{
int L, R;
L = 2;
R = 10;
Console.WriteLine(CountNum(R) - CountNum(L - 1));
}
}
/* This code is contributed by PrinciRaj1992 */
输出:
4
时间复杂度: 0 18时最多会有18 *(180)*(180)* 2个计算