我正在寻找一个旧的编码竞赛的解决方案,我想知道他们是如何找到这个解决方案的。
问题是这样的:计算numStart-numEnd范围内有多少个唯一数字可被给定质数列表中的至少一个质数除。
首先,我想“当然,让我们做一个遍历numStart-numEnd范围的for循环,并检查我是否可以将迭代器除以至少一个质数”,该方法有效,但是速度太慢。 ..那就是我决定检查答案的时候。
我的代码:
# numStart: Start from number
# numEnd: End on number
# numOfPrimes: How many primes will we be checking
numStart,numEnd,numOfPrimes = map(int, input().split())
primes = list(map(int, input().split()))
# Input can look like this:
# >21 180 4
# >7 3 13 2
counter = 0
for testNum in range(numStart, numEnd + 1):
for prime in primes:
if testNum % prime == 0:
counter += 1
break
print(counter)
# Output would look like this:
# >118
解决方案:
from itertools import combinations
# numStart: Start from number
# numEnd: End on number
# numOfPrimes: How many primes will we be checking
numStart,numEnd,numOfPrimes = map(int, input().split())
primes = list(map(int, input().split()))
# Input can look like this:
# >21 180 4
# >7 3 13 2
result = 0
for j in range(1,numOfPrimes+1):
for c in combinations(primes, j):
num = 1
for x in c: num *= x
result += (-1)**(len(c)+1) * (numEnd//num - (numStart-1)//num)
print(result)
# Output would look like this:
# >118
我的问题确实是这个人实际上是如何解决的?这是什么类型的数学,为什么起作用?
如果您至少可以带领我朝正确的方向前进,我将非常感激!
答案 0 :(得分:1)
这是部分代码的简短摘要。
给定代码中有两个主要思想。第一个想法是,给定正整数num
(不一定是素数),从numStart
到numEnd
被num
整除的数字的计数是
numEnd//num - (numStart-1)//num
这是因为num
从1
到numStart
的整数是(numStart-1)//num
,而从1
到numEnd
的整数是{{1} }。 (我会让您找出这些公式如何正确处理这些范围的最终值。)
这是第二个想法。该公式适用于给定列表中的每个素数。但是问题是要求计数范围内的数字可以被该列表中的“ 至少一个素数”整除。如果仅将每个素数的计数相加,我们将计算可被多个素数整除的次数。处理这些多个计数的标准方法是Inclusion–exclusion principle。如果您对这种问题感兴趣,则应该阅读该文章。代码行
numEnd//num
使for j in range(1,numOfPrimes+1):
for c in combinations(primes, j):
成为质数列表的非空子集。我上面给您的公式用于查找子集中素数的每个乘积的计数,并将因数c
乘以进行正确的包含/排除。然后添加所有这些产品。如果您不理解最后一部分,请阅读包含-排除文章。我应该补充一点,基本数论告诉我们,当且仅当素数的乘积除以该数时,不同素数的成员集都对数进行除数-这就是问题中“素数”限制的原因。 / p>
关于人如何解决这个问题,计算机科学表明,没有确定方法来解决问题的算法。问题解决者只是利用他们的知识,经验,创造力和毅力来坚持下去,直到问题解决为止。乔治·波利亚(George Polya)的《 如何解决问题》()是一本关于如何解决问题的经典著作。我向您强烈推荐这本书-平装且价格便宜。