数学:第170题 小C的数字倍数问题 | 豆包MarsCode AI刷题

96 阅读4分钟

1. 问题描述

小U对数字倍数问题很感兴趣,她想知道在区间[ l, r ]内,有多少个数是a的倍数,或者是b的倍数,或者是c的倍数。你需要帮小U计算出这些数的个数。

2. 问题背景

这个问题是一个典型的数学问题,涉及到数论中的倍数和最小公倍数(LCM)的概念。在编程中,这类问题可以通过数学公式和算法来解决,是算法竞赛和面试中的常见题型。

3. 概念解释

  • 倍数:一个数能够被另一个数整除,那么这个数就是另一个数的倍数。
  • 最小公倍数(LCM):两个或多个整数共有倍数中最小的一个。
  • 容斥原理:在计算多个集合的并集时,为了避免重复计算,需要减去交集的元素数量。公式如下:

[ |A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C| ]

4. 思路分析

要解决这个问题,我们可以采用以下步骤:

  • 首先,计算区间[ l, r ]内a、b、c各自的倍数个数。
  • 然后,计算a和b、a和c、b和c的公倍数个数,因为这些数在前面的计算中被重复计算了。
  • 最后,计算a、b、c的公倍数个数,因为这些数在计算a和b、a和c、b和c的公倍数时被减去了两次,需要加回来。

5. 代码详解

首先,导入了Python的math模块,以便使用gcd函数来计算最大公约数,这是计算最小公倍数的必要步骤。

import math

接下来,定义一个计算两个数最小公倍数的函数lcm。这个函数利用了最大公约数gcd来计算最小公倍数,公式为lcm(a, b) = |a*b| / gcd(a, b)

def lcm(x, y):
    return x * y // math.gcd(x, y)

然后,定义主要的函数solution,它接受五个参数:三个数a、b、c,以及一个区间的起始和结束值l和r。

def solution(a: int, b: int, c: int, l: int, r: int) -> int:

在函数内部,首先计算区间[ l, r ]内a的倍数的个数。这是通过将r除以a和(l-1)除以a的结果相减得到的。

    count_a = (r // a) - ((l - 1) // a)

同样的计算方法,得到了b和c的倍数个数。

    count_b = (r // b) - ((l - 1) // b)
    count_c = (r // c) - ((l - 1) // c)

接下来,计算a和b的公倍数个数。首先计算a和b的最小公倍数lcm_ab,然后用同样的方法计算公倍数的个数。

    lcm_ab = lcm(a, b)
    count_ab = (r // lcm_ab) - ((l - 1) // lcm_ab)

对a和c、b和c也进行了相同的计算。

    lcm_ac = lcm(a, c)
    count_ac = (r // lcm_ac) - ((l - 1) // lcm_ac)
    
    lcm_bc = lcm(b, c)
    count_bc = (r // lcm_bc) - ((l - 1) // lcm_bc)

计算a、b和c的公倍数个数。这需要先计算a和b的最小公倍数与c的最小公倍数。

    lcm_abc = lcm(lcm_ab, c)
    count_abc = (r // lcm_abc) - ((l - 1) // lcm_abc)

使用容斥原理,将所有的计数结果合并起来,得到最终的结果。

    result = count_a + count_b + count_c - count_ab - count_ac - count_bc + count_abc
    return result

最后,通过几个测试用例来验证我们的函数是否正确。

if __name__ == "__main__":
    print(solution(2, 3, 4, 1, 10) == 7)
    print(solution(5, 7, 11, 15, 100) == 34)
    print(solution(1, 1, 1, 1, 1000) == 1000)

6. 个人思考

在解决这个问题时,我首先考虑了如何避免重复计算。容斥原理是一个非常有效的工具,它可以帮助我们在计算多个集合的并集时避免重复元素的计算。在实际编程中,我注意到了Python中的整数除法//和浮点除法/的区别,以及如何正确地使用它们。

此外,我也思考了代码的可读性和效率。通过将计算最小公倍数的函数lcm单独提取出来,我使得主函数solution更加清晰易懂。同时,我也注意到了在计算倍数时,使用整数除法可以避免浮点数的精度问题。

最后,我认为这个问题不仅仅是一个编程问题,它还涉及到了数学知识和逻辑思维。在解决这类问题时,我们需要将数学概念转化为算法,并且需要考虑到算法的效率和准确性。这是一个将理论知识应用到实际问题中的过程,也是编程的魅力所在。