找到给定范围内的交叉点?

时间:2017-01-21 01:51:35

标签: c++ algorithm

假设N(N <= 100000)个元素a1,a2,...,a的数组,并且给出L,R的范围,其中1 <= L <= R <= N,则需要为了得到给定范围内的值的数量,这些值可以被给定的集合S中的至少一个数字整除,该集合可以是{1,2,......,10}的任何子集。必须使用快速方法,因为它可能会要求您提供多个范围和多个S(许多查询Q,Q <= 100000),因此每次循环值都会非常慢。

我想在10个N元素的数组中存储大集合{1,2,....,10}中每个数字可被整除的值的数量,并进行累加求和得到可被整除的值的数量在O(1)时间内任何范围内的任何特定数字,例如,如果它需要获得可被以下至少一项整除的值的数量:2,3,5,那么我添加每个可被整除的值的数量然后删除交叉点,但我没有正确地弄清楚如何计算交叉点,每次没有2 ^ 10或2 ^ 9计算,这也将非常慢(并且可能耗费大量内存),因为它可能会完成100000次,有什么想法吗?

1 个答案:

答案 0 :(得分:0)

你的想法是正确的。您可以使用包含 - 排除原则和前缀和来查找答案。你需要再做一次观察。

如果集合中有一对数字aba除以b,我们可以删除b而不更改答案查询(实际上,如果是b | x,那么a | x)。因此,我们总是得到一个集合,使得任何元素都不会划分任何其他元素。

此类掩码的数量小于2^10。事实上,它是102。这是计算它的代码:

def good(mask):
    for i in filter(lambda b: mask & (1 << (b - 1)), range(1, 11)):
        if (any(i % j == 0 for j in filter(lambda b: mask & (1 << (b - 1)), range(1, i)))):
            return False            
    return True

print(list(filter(good, range(1, 2 ** 10)))))

因此,我们预处理需要大约100N个操作和数字来存储(它看起来相当小)。

此外,任何“好”掩码中都有大多数5个元素(可以使用上面的代码进行检查)。因此,我们可以使用2^5操作来回答每个查询。