【问题标题】:Count of numbers between A and B (inclusive) that have sum of digits equal to SA 和 B(含)之间数字之和等于 S 的数字计数
【发布时间】:2014-01-24 17:12:57
【问题描述】:

问题是找出 A 和 B(含)之间数字之和等于 S 的数字的计数。

同时打印 A 和 B(含)之间的最小数字。

输入:

由 A,B,S 组成的单行。

输出:

两行。

在第一行中,A 和 B 之间数字和等于 S 的整数个数。

第二行是 A 和 B 之间最小的数字。

约束:

1

1

来源:Hacker Earth

我的解决方案仅适用于他们输入的 30 pc。什么是最好的解决方案?

我现在使用的算法计算最小数字的总和,然后在十位数字的每次变化时再次计算总和。 以下是 Python 中的解决方案:

def sum(n):
    if (n<10):return n
    return n%10 + sum(n/10)

stri = raw_input()

min = 99999
stri = stri.split(" ")

a= long  (stri[0])
b= long  (stri[1])
s= long  (stri[2])

count= 0
su = sum(a)

while a<=b :        
if (a % 10 == 0 ):
    su = sum(a)
    print a 
if ( s == su):
    count+=1
    if (a<= min):
        min=a 
a+=1
su+=1
print count 
print min 

【问题讨论】:

  • 您的解决方案在哪里?
  • 如果你愿意,我会在这里发布。
  • 这就是这个网站背后的想法。 “向我们展示您的代码,我们会看到有什么问题(或问题出在哪里)。”
  • @Mario 更新了问题

标签: algorithm math


【解决方案1】:

这里有两个单独的问题:找到具有正确数字和的数字之间的最小数字,以及找到具有该数字和的范围内的值的数量。我将分别讨论这些问题。

用数字和 S 计算 A 和 B 之间的值。

解决这个问题的一般方法如下:

  • 用数字和 S 计算小于或等于 A - 1 的值的数量。
  • 用数字和 S 计算小于或等于 B 的值的个数。
  • 从第二个数字中减去第一个数字。

为此,我们应该能够使用动态编程方法。我们将尝试回答以下形式的查询:

有多少个D位数字,第一个数字是k,谁的数字总和是S?

我们将创建一个表 N[D, k, S] 来保存这些值。我们知道 D 最多为 16,S 最多为 136,因此该表将只有 10 × 16 × 136 = 21,760 个条目,这还不错。要填写它,我们可以使用以下基本情况:

  • N[1, S, S] = 1 表示 0 ≤ S ≤ 9,因为只有一个一位数的总和小于 10。
  • N[1, k, S] = 0 for 0 ≤ S ≤ 9 if k ≠ S,因为第一个数字不是特定总和的一位数的总和不会达到某个值。
  • 对于 10 ≤ S ≤ 135,N[1, k, S] = 0,因为对于任何大于一位数的 k,没有一位数的总和恰好等于 S。
  • 对于任何 S

然后,我们可以使用以下逻辑来填充其他表项:

  • N[D + 1, k, S] = sum(i from 0 to 9) N[D, i, S - k]。

这表示第一个数字为 k 且总和为 S 的 (D+1) 位数字的数量由总和为 S - k 的 D 位数字的数量给出。总和为 S - k 的 D 位数字的数量由总和为 S - k 的第一个数字是 0、1、2、...、9 的 D 位数字的数量给出,所以我们有总结一下。

填写这个 DP 表只需要 O(1) 的时间,事实上,如果你真的很关心时间,你可以预计算它并将它硬编码到程序中。

那么我们如何使用这个表呢?好吧,假设我们想知道与 S 相加的数字有多少小于或等于某个数字 X。为此,我们可以一次处理一个 X 的数字。让我们一次将 X 写为 d1 ... dn。我们可以从 N[n, d1, S] 开始。这为我们提供了第一个数字为 d1 且总和为 S 的 n 位数字的数量。这可能会高估小于或等于 X 且总和为 S 的值的数量。例如,如果我们的数字是 21,111,并且我们想要总和正好为 12 的值的数量,那么查找此表值将为我们提供像 29,100 这样以 2 开头且长度为五位的数字的误报,但仍然是大于 X。为了解决这个问题,我们可以移动到数字 X 的下一位数字。由于第一位数字是 2,所以该数字中的其余数字总和必须为 10。此外,由于 X 的下一位数字(21,111) 是 1,我们现在可以从总数中减去以 2、3、4、5、...、9 开头的 4 位数字,加起来为 10。然后我们可以重复这个过程一位数一次。

更一般地说,我们的算法如下。让 X 是我们的数字, S 是目标总和。写 X = d1d2...dn 并计算以下内容:

# Begin by starting with all numbers whose first digit is less than d[1].
# Those count as well.
result = 0
for i from 0 to d[1]:
    result += N[n, i, S]

# Now, exclude everything whose first digit is d[1] that is too large.
S -= d[1]
for i = 2 to n:
    for j = d[i] to 8:
        result -= N[n, d[i], S]
    S -= d[i]

result 的值将是小于或等于 X 且总和正好为 S 的值的数量。该算法最多只能运行 16 次迭代,因此它应该非常快。此外,使用这个算法和前面的减法技巧,我们可以用它来计算 A 和 B 之间有多少个值加起来正好是 S。

求 [A, B] 中数字和 S 的最小值。

我们可以对我们的 DP 表使用类似的技巧来找到大于 A 且总和正好为 S 的最小数字。我将把细节留作练习,但作为提示,一次计算一个数字,试图找到 DP 表返回非零值的最小数字。

希望这会有所帮助!

【讨论】:

  • 假设你必须数到 19,总和为 5。在这种情况下,答案应该是 2。单个数字 5 和数字 14。但是从我们的查找表中N 我们只能得到 14,因为我们只搜索以 1 开头的数字。
  • @Sohaib 这是一个很好的观点。我猜如果这个数字有 n 位,你还要检查所有 n-1 位数字、所有 n-2 位数字等。我认为这会解决这个问题。
  • @Sohaib 我已经更新了伪代码。我还没有测试过,但我认为它应该可以工作。
  • @templatetypedef 伪代码的最后第三行,不应该是“for j = d[i]+1 to 9:”而不是“for j = d[i] to 8: “?因为我们减去 i 处的数字大于 d[i] 的所有结果,然后将 d[i] 固定在位置 i 并对数字 i+1 执行相同的操作。例如说数字是 31245,这里 d[1]=3,d[2]=1,d[3]=2,d[4]=4,d[5]=5。现在从 i=2 开始,这里 d[i=2]=1,因此减去 1
猜你喜欢
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 2022-10-05
  • 1970-01-01
相关资源
最近更新 更多