![](/img/trans.png)
[英]how to count the number divisible by N in given range (A to B) for multiple cases (C) in python
[英]How do I count from a given range a number that is not divisible by any element of the array?
问题陈述:
在 1 到 1000000000000000000 之间,除了给定数字的倍数之外,还有多少数字可以快速找到并使用 memory?
例如,1 到 1000000000000000000 之间有多少数字不是[29516, 15, 63315, 94, 43, 77, 33422, 84834, 43803, 61310]
? 如果您能给我 python 中的代码,将会很有帮助。
# Python3 program for the above approach
# Function to find the non-multiples
# till k
def findNonMultiples(arr, n, k):
# Stores all unique multiples
multiples = set([])
# Iterate the array
for i in range(n):
# For finding duplicates
# only once
if (arr[i] not in multiples):
# Inserting all multiples
# into the set
for j in range(1, k // arr[i] + 1):
multiples.add(arr[i] * j)
# Returning only the count of
# numbers that are not divisible
# by any of the array elements
return k - len(multiples)
# Function to count the total values
# in the range [L, R]
def countValues(arr, N, L, R):
# Count all values in the range
# using exclusion principle
return (findNonMultiples(arr, N, R) -
findNonMultiples(arr, N, L - 1))
# Driver Code
if __name__ == "__main__":
arr = [ 29516,15,63315,94,43,77,33422,84834,43803,61310 ]
N = len(arr)
L = 1
R = 1000000000000000000
# Function Call
print( countValues(arr, N, L, R))
# This code is contributed by chitranayal
这段代码太慢了,使用了很多memory。 我该如何改进它?
这是一种我没有试图证明的数学猜想方法。 我不保证得到的结果是完全正确的。
我的想法是把 select 的值从给定的列表中一个一个地从范围中移除,并计算每次要移除的数字个数。 根据OP提供的例子,先从10**18中去掉29516的倍数,去掉的个数为:
>>> hi = 10 ** 18
>>> hi // 29516
33879929529746
第二次删除 15。 考虑到15和29516的最小公倍数是442740,我们需要去掉下面的数:
>>> hi // 15 - hi // 442740
66664408004698017
第三次去掉65,要去掉的数字是:
>>> hi // 63315 - hi // lcm(29516, 63315) - hi // lcm(15, 63315) + hi // lcm(29516, 15, 63315)
0
这里 lcm 用于求最小公倍数。
示例到此结束。 这是我的猜测:假设已经删除的号码列表是nums
,当前要删除的号码是num
。 需要去除的数字数量用Python代码表示为:
hi // num
- sum(hi // lcm(*comb, num) for comb in combinations(nums, 1))
+ sum(hi // lcm(*comb, num) for comb in combinations(nums, 2))
- ...
+/- sum(hi // lcm(*comb, num) for comb in combinations(nums, len(nums)))
以下是实现代码:
from math import lcm
from itertools import combinations
def num_removed(num, nums, hi):
for i in range(0, len(nums) + 1, 2):
yield sum(hi // lcm(*comb, num) for comb in combinations(nums, i))
for i in range(1, len(nums) + 1, 2):
yield -sum(hi // lcm(*comb, num) for comb in combinations(nums, i))
def main(nums, hi):
return hi - sum(sum(num_removed(num, nums[:i], hi)) for i, num in enumerate(nums))
计算结果:
>>> main([29516, 15, 63315, 94, 43, 77, 33422, 84834, 43803, 61310], 10 ** 18)
890153441245772172
上面的猜想是基于下界为1的特殊情况。如果下界大于1,一个简单的实现方法是计算两次要去除的数字的个数,然后计算它们的差:
def num_is_multiples(nums, hi):
return sum(sum(num_removed(num, nums[:i], hi)) for i, num in enumerate(nums))
def num_non_multiples(nums, lo, hi):
return hi - lo + 1 - (num_is_multiples(nums, hi) - num_is_multiples(nums, lo - 1))
计算结果:
>>> num_non_multiples([29516, 15, 63315, 94, 43, 77, 33422, 84834, 43803, 61310], 200, 10 ** 18)
890153441245771994
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.