给定一个整数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
先决条件:数字DP
天真的方法:
一种在 O(N) 中线性遍历从 0 到 N 的所有元素并计算 log(n) 中的数字总和(其中 n 是该数字中的数字位数)的简单方法,对于 N 的大量输入将失败。
有效的方法:
- 我们可以使用动态规划,这是一个非常有用的技术,即 digit-dp 来解决这个问题。
- 因此,我们不是保留非零整数的记录,而是保留可以保留在不同索引处的零记录,即变量 K 中的idx 。我们可以保留的零的数量最初可以通过将 K 中的位数减去N。
- 我们将 N 的所有数字保存到一个向量中,比如数字。
- 现在,我们通过分析 K 来计算我们可以保留在索引 idx 处的元素范围。
- 假设在索引idx 处,我们剩下K = 1 (非零值),那么我们放置元素的范围是[0, j] ,其中 j 是由从当前索引获得的紧值决定的上限来自矢量数字的数字。
- 如果在idx ,我们剩下K = 0 ,那么我们的范围变成[1, j]因为我们不能在那里输入 0 。
- 现在,还有一个参数sum ,它将计算一个数字的数字总和,直到基本案例成功命中。
- 此外,使用布尔映射将存储已经计算的所有奇数和,因此它给出了不同的奇数和。
- 重复将是:
其中 j = 数字 [idx] 如果紧 = 0,否则 j = 9 - 基本情况:
- 当idx = digits.size() 时, K == 0且sum为奇数。
我们将总和标记为真并返回 1 否则返回 0。 - 如果idx >digits.size()则返回 0。
- 当idx = digits.size() 时, K == 0且sum为奇数。
所以我们创建了一个 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
Javascript
输出:
12
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。