给定一个整数N和一个数字K ,任务是找出从0到N的总数,这些总数恰好具有K个非零数字,并且这些数字的总和应为奇数,并且该和应是不同的。 N可以大到10 ^ 18 。
例子:
Input : N = 10, K = 1
Output : 5
The numbers which follow the conditions are ->
1, 3, 5, 7 and 9
The digit sum of 10 that is (1+0) = 1 is also odd, but 1 is already included in our count.
Input : N = 100, K = 2
Output : 8
先决条件:Digit-DP
天真的方法:
对于N的大量输入,天真的方法无法在O(N)中从0到N的所有元素进行线性遍历并计算log(n)中的位数之和,其中n是该数字中的位数。
高效方法:
- 我们可以使用动态编程,这是非常有用的技术,它是digit-dp来解决此问题。
- 因此,除了保留非零整数的记录之外,我们还保留零变量的记录,我们可以将其保留在变量K的不同索引idx上。我们可以保留的零数目可以通过将K中的位数减去K来最初找到。 N.
- 我们将N的所有数字都放入一个向量,即digits 。
- 现在,我们通过分析K来计算可保持在索引idx处的元素范围。
- 假设在索引idx处,我们剩下K = 1 (一个非零值),则我们放置元素的范围是[0,j] ,其中j是由从当前索引获得的紧密值确定的上限矢量数字中的数字。
- 如果在idx处,我们剩下K = 0 ,则我们的范围变为[1,j],因为我们不能在此处输入0。
- 现在,还要使用一个参数sum ,它将计算数字的数字总和,直到基本情况成功命中为止。
- 另外,使用了一个布尔图,它将存储所有已经计算出的奇数和,因此它给出了不同的奇数和。
- 重复发生将是:
其中j = digits [idx],如果紧密= 0,否则j = 9 - 基本情况:
- 当idx = digits.size()时, K == 0 ,总和为奇数。
我们将总和标记为true,然后返回1,否则返回0。 - 如果idx> digits.size(),则返回0。
- 当idx = digits.size()时, K == 0 ,总和为奇数。
因此,我们创建了一个DP表,即DP [idx] [K] [tight] [sum] ,该表将存储上述重复产生的结果,并通过将其记忆到该DP表中来返回计数。
下面是上述方法的实现:
C++
// C++ program to Count the numbers having
// exactly K non-zero digits and sum
// of digits are odd and distinct.
#include
using namespace std;
// To store digits of N
vector digits;
// visited map
bool vis[170] = { false };
// DP Table
int dp[19][19][2][170];
// Push all the digits of N into
// digits vector
void ConvertIntoDigit(int n)
{
while (n) {
int dig = n % 10;
digits.push_back(dig);
n /= 10;
}
reverse(digits.begin(), digits.end());
}
// Function returns the count
int solve(int idx, int k,
int tight, int sum)
{
// If desired number is formed
// whose sum is odd
if (idx == digits.size()
&& k == 0 && sum & 1) {
// If it is not present in map,
// mark it as true and return 1
if (!vis[sum]) {
vis[sum] = 1;
return 1;
}
// Sum is present in map already
return 0;
}
// Desired result not found
if (idx > digits.size()) {
return 0;
}
// If that state is already calculated
// just return that state value
if (dp[idx][k][tight][sum]) {
return dp[idx][k][tight][sum];
}
// Upper limit
int j;
if (tight == 0) {
j = digits[idx];
}
else {
j = 9;
}
// To store the count of
// desired numbers
int cnt = 0;
// If k is non-zero, i ranges from
// 0 to j else [1, j]
for (int i = (k ? 0 : 1);
i <= j; i++) {
int newtight = tight;
if (i < j) {
newtight = 1;
}
// If current digit is 0, decrement
// k and recurse sum is not changed
// as we are just adding 0 that
// makes no difference
if (i == 0)
cnt += solve(idx + 1, k - 1,
newtight, sum);
// If i is non zero, then k remains
// unchanged and value is added to sum
else
cnt += solve(idx + 1, k, newtight,
sum + i);
}
// Memoize and return
return dp[idx][k][tight][sum] = cnt;
}
// Driver code
int main()
{
// K is the number of exact non-zero
// elements to have in number
int N, k;
N = 169, k = 2;
// break N into its digits
ConvertIntoDigit(N);
// We keep record of 0s we need to
// place in the number
k = digits.size() - k;
cout << solve(0, k, 0, 0);
}
Java
// Java program to count the numbers having
// exactly K non-zero digits and sum
// of digits are odd and distinct.
import java.util.*;
class GFG{
// To store digits of N
static Vector digits = new Vector();
// visited map
static boolean []vis = new boolean[170];
// DP Table
static int [][][][]dp = new int[19][19][2][170];
// Push all the digits of N into
// digits vector
static void ConvertIntoDigit(int n)
{
while (n > 0)
{
int dig = n % 10;
digits.add(dig);
n /= 10;
}
Collections.reverse(digits);
}
// Function returns the count
static int solve(int idx, int k,
int tight, int sum)
{
// If desired number is formed
// whose sum is odd
if (idx == digits.size() &&
k == 0 && sum % 2 == 1)
{
// If it is not present in map,
// mark it as true and return 1
if (!vis[sum])
{
vis[sum] = true;
return 1;
}
// Sum is present in map already
return 0;
}
// Desired result not found
if (idx > digits.size())
{
return 0;
}
// If that state is already calculated
// just return that state value
if (dp[idx][k][tight][sum] > 0)
{
return dp[idx][k][tight][sum];
}
// Upper limit
int j;
if (idx < digits.size() && tight == 0)
{
j = digits.get(idx);
}
else
{
j = 9;
}
// To store the count of
// desired numbers
int cnt = 0;
// If k is non-zero, i ranges from
// 0 to j else [1, j]
for(int i = (k > 0 ? 0 : 1); i <= j; i++)
{
int newtight = tight;
if (i < j)
{
newtight = 1;
}
// If current digit is 0, decrement
// k and recurse sum is not changed
// as we are just adding 0 that
// makes no difference
if (i == 0)
cnt += solve(idx + 1, k - 1,
newtight, sum);
// If i is non zero, then k remains
// unchanged and value is added to sum
else
cnt += solve(idx + 1, k, newtight,
sum + i);
}
// Memoize and return
return dp[idx][k][tight][sum] = cnt;
}
// Driver code
public static void main(String[] args)
{
// K is the number of exact non-zero
// elements to have in number
int N, k;
N = 169; k = 2;
// break N into its digits
ConvertIntoDigit(N);
// We keep record of 0s we need to
// place in the number
k = digits.size() - k;
System.out.print(solve(0, k, 0, 0));
}
}
// This code is contributed by amal kumar choubey
Python3
# Python3 program to Count the numbers having
# exactly K non-zero digits and sum
# of digits are odd and distinct.
# To store digits of N
digits = []
# visited map
vis = [False for i in range(170)]
# DP Table
dp = [[[[0 for l in range(170)] for k in range(2)] for j in range(19)] for i in range(19)]
# Push all the digits of N into
# digits vector
def ConvertIntoDigit(n):
while (n > 0):
dig = n % 10;
digits.append(dig);
n //= 10;
digits.reverse()
# Function returns the count
def solve(idx, k, tight, sum):
# If desired number is formed
# whose sum is odd
if (idx == len(digits) and k == 0 and sum % 2 == 1):
# If it is not present in map,
# mark it as true and return 1
if (not vis[sum]):
vis[sum] = True;
return 1;
# Sum is present in map already
return 0;
# Desired result not found
if (idx > len(digits)):
return 0;
# If that state is already calculated
# just return that state value
if (dp[idx][k][tight][sum]):
return dp[idx][k][tight][sum];
# Upper limit
j = 0;
if (idx
C#
// C# program to count the numbers having
// exactly K non-zero digits and sum
// of digits are odd and distinct.
using System;
using System.Collections.Generic;
class GFG{
// To store digits of N
static List digits = new List();
// visited map
static bool []vis = new bool[170];
// DP Table
static int [,,,]dp = new int[ 19, 19, 2, 170 ];
// Push all the digits of N into
// digits vector
static void ConvertIntoDigit(int n)
{
while (n > 0)
{
int dig = n % 10;
digits.Add(dig);
n /= 10;
}
digits.Reverse();
}
// Function returns the count
static int solve(int idx, int k,
int tight, int sum)
{
// If desired number is formed
// whose sum is odd
if (idx == digits.Count &&
k == 0 && sum % 2 == 1)
{
// If it is not present in map,
// mark it as true and return 1
if (!vis[sum])
{
vis[sum] = true;
return 1;
}
// Sum is present in map already
return 0;
}
// Desired result not found
if (idx > digits.Count)
{
return 0;
}
// If that state is already calculated
// just return that state value
if (dp[idx, k, tight, sum] > 0)
{
return dp[idx, k, tight, sum];
}
// Upper limit
int j;
if (idx < digits.Count && tight == 0)
{
j = digits[idx];
}
else
{
j = 9;
}
// To store the count of
// desired numbers
int cnt = 0;
// If k is non-zero, i ranges from
// 0 to j else [1, j]
for(int i = (k > 0 ? 0 : 1); i <= j; i++)
{
int newtight = tight;
if (i < j)
{
newtight = 1;
}
// If current digit is 0, decrement
// k and recurse sum is not changed
// as we are just adding 0 that
// makes no difference
if (i == 0)
cnt += solve(idx + 1, k - 1,
newtight, sum);
// If i is non zero, then k remains
// unchanged and value is added to sum
else
cnt += solve(idx + 1, k, newtight,
sum + i);
}
// Memoize and return
return dp[idx, k, tight, sum] = cnt;
}
// Driver code
public static void Main(String[] args)
{
// K is the number of exact non-zero
// elements to have in number
int N, k;
N = 169; k = 2;
// break N into its digits
ConvertIntoDigit(N);
// We keep record of 0s we need to
// place in the number
k = digits.Count - k;
Console.Write(solve(0, k, 0, 0));
}
}
// This code is contributed by amal kumar choubey
输出:
12
如果您希望与行业专家一起参加现场课程,请参阅《 Geeks现场课程》和《 Geeks现场课程美国》。