📌  相关文章
📜  除数为素数的[L,R]范围内的数字总和(1)

📅  最后修改于: 2023-12-03 15:28:51.182000             🧑  作者: Mango

除数为素数的[L,R]范围内的数字总和

简介

本文介绍了如何计算除数为素数的[L,R]范围内的数字总和。这是一个常见的问题,例如在质数分解中,需要计算一个数的素数因子的总和。

思路

我们可以枚举[L,R]内的每个数字x,判断它是否是质数的因子。当且仅当x是质数的因子时,我们将其加入到总和中。为了判断一个数是否是质数,可以使用试除法或者埃拉托斯特尼筛法。

代码实现
试除法

试除法即对于每个数字x,枚举[2, x-1]的每个数y,判断y是否是x的因子。如果找到x的非1和非x本身的因子,那么x就不是质数。

def is_prime(num):
    if num < 2:  # 0和1不是质数
        return False
    for i in range(2, num):
        if num % i == 0:
            return False
    return True

def prime_factor_sum(L, R):
    res = 0
    for x in range(L, R+1):
        for y in range(2, x):
            if x % y == 0 and is_prime(y):
              res += y
              break  # 因为重复的因子只能算一次,所以找到一个就可以退出了
    return res

时间复杂度

嵌套循环的时间复杂度是O((R-L)^2),而判断一个数是否是素数的时间复杂度是O(sqrt(x)),所以总的时间复杂度是O((R-L)^2 * sqrt(R))。这个算法在L和R都比较大的情况下,效率非常低下。

埃拉托斯特尼筛法

埃拉托斯特尼筛法是一种用来求小于等于n的所有质数的方法,在本问题中可以用来优化判断一个数是否是素数的过程。

具体来说,我们可以用一个长度为R的布尔数组is_prime来表示[1, R]内的数字是否是素数。初始化时,将is_prime中所有元素标记为True。

接着我们枚举[2, sqrt(R)]内的每个数字i,如果i是素数,我们就将is_prime中i的倍数(除了i本身)全部标记为False。

最后,我们就可以使用is_prime来快速判断一个数是否是素数了。判断一个数字x是否是素数,只需要判断is_prime[x]是否为True。

def prime_factor_sum(L, R):
    res = 0
    is_prime = [True] * (R+1)
    is_prime[0], is_prime[1] = False, False
    for i in range(2, int(R**0.5)+1):
        if is_prime[i]:  # 如果i是素数,将其倍数全部标记为False
            for j in range(i*i, R+1, i):
                is_prime[j] = False
    
    for x in range(L, R+1):
        for y in range(2, x):
            if x % y == 0 and is_prime[y]:
              res += y
              break
    return res

时间复杂度

初始化is_prime的时间复杂度是O(R),筛掉每个素数的时间复杂度也是O(R),嵌套循环的时间复杂度是O((R-L)^2),所以总的时间复杂度是O(R + (R-L)^2). 当L和R都很大时,这个算法的效率仍然很低,但是比试除法快很多。