📌  相关文章
📜  计算范围 [L, R] 内不能被前 K 个素数整除的整数(1)

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

题目介绍

给定一个区间 $[L, R]$ 和一个参数 $k$,请计算出该区间内所有不能被前 $k$ 个素数整除的整数的个数。

解题思路

首先,我们需要求出前 $k$ 个素数,可以使用筛法求素数的方法。

对于每个整数 $x\in[L, R]$,我们枚举前 $k$ 个素数 $p_i$,如果 $x$ 能被 $p_i$ 整除,则不符合条件。因此,我们只需要统计出有多少个数不能被前 $k$ 个素数整除即可。

具体地,假设前 $k$ 个素数分别为 $p_1, p_2, \cdots, p_k$,则区间 $[L, R]$ 内不能被这些素数整除的整数个数等于:

$$(R-L+1)-\sum\limits_{i=1}^k\lfloor\dfrac{R}{p_i}\rfloor+\sum\limits_{1\le i<j\le k}\lfloor\dfrac{R}{p_i p_j}\rfloor-\sum\limits_{1\le i<j<k\le k}\lfloor\dfrac{R}{p_i p_j p_k}\rfloor+\cdots+(-1)^k\lfloor\dfrac{R}{p_1 p_2 \cdots p_k}\rfloor$$

其中 $\lfloor x\rfloor$ 表示下取整函数。

代码实现

from math import sqrt

def count(L: int, R: int, k: int) -> int:
    primes = []  # 存储前 k 个素数
    is_prime = [True] * (R + 1)
    for i in range(2, R + 1):
        if is_prime[i]:
            primes.append(i)
            if len(primes) == k:
                break
            for j in range(i * i, R + 1, i):
                is_prime[j] = False

    ans = R - L + 1
    for mask in range(1, 1 << k):
        prod = 1
        cnt = 0
        for i in range(k):
            if mask & (1 << i):
                prod *= primes[i]
                cnt += 1
        if cnt % 2 == 0:
            ans += (R // prod - (L - 1) // prod)
        else:
            ans -= (R // prod - (L - 1) // prod)

    return ans

L, R, k = map(int, input().split())
print(count(L, R, k))

代码说明:

  • 首先求出前 $k$ 个素数,存储在列表 primes 中;
  • 然后枚举所有的子集,计算出对应的倍数的个数;
  • 最后根据容斥原理,计算出不能被前 $k$ 个素数整除的整数个数。

复杂度分析

求解前 $k$ 个素数的时间复杂度为 $O(R\log{\log{R}})$,枚举所有子集的时间复杂度为 $O(2^k)$,计算对应倍数的个数的时间复杂度为 $O(\log{R})$。因此,该算法的时间复杂度为 $O(R\log{\log{R}}+2^k\log{R})$。

空间复杂度为 $O(R)$(用于存储前 $k$ 个素数或者用于筛选素数)。

参考资料