题目解析:小C的数字倍数问题 | 豆包MarsCode AI 刷题

138 阅读3分钟

问题描述

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

解题思路

  1. 计算单个数的倍数:首先,我们可以计算在区间 [l, r] 内,有多少个数是 a 的倍数,有多少个数是 b 的倍数,有多少个数是 c 的倍数。
  2. 使用容斥原理:为了避免重复计算,我们需要使用容斥原理来计算这些数的并集。

步骤:

  1. 计算倍数的数量

设 f(x)f(x) 为在区间 [1,x][1,x] 中是 nn 的倍数的数字的数量:

             f(n,x)=⌊xn⌋f(n,x)=⌊nx​⌋

因此,在区间 [l,r][l,r] 中是 nn 的倍数的数字的数量为:

      f(n,l,r)=f(n,r)−f(n,l−1)=⌊rn⌋−⌊l−1n⌋f(n,l,r)=f(n,r)−f(n,l−1)=⌊nr​⌋−⌊nl−1​⌋

2. 使用包含-排除原理

设 NaNa​、NbNb​ 和 NcNc​ 分别为区间 [l,r][l,r] 中 aa、bb 和 cc 的倍数的数量。 计算 NaNa​、NbNb​、NcNc​:

    -   Na=f(a,l,r)Na​=f(a,l,r)
    -   Nb=f(b,l,r)Nb​=f(b,l,r)
    -   Nc=f(c,l,r)Nc​=f(c,l,r)

2. 计算两个同事的倍数

计算 NabNab​、NacNac​、NbcNbc​,其中 NabNab​ 是同时是 aa 和 bb 的倍数的数量,使用最小公倍数(LCM):

    -   Nab=f(lcm(a,b),l,r)Nab​=f(lcm(a,b),l,r)
    -   同理计算 NacNac​ 和 NbcNbc​。

2. 计算三个同事的倍数

计算 NabcNabc​:

    -   Nabc=f(lcm(a,b,c),l,r)Nabc​=f(lcm(a,b,c),l,r)

2. 应用包含-排除原理

根据包含-排除原理,最终计算数量为:

   N=Na+Nb+Nc−Nab−Nac−Nbc+NabcN=Na​+Nb​+Nc​−Nab​−Nac​−Nbc​+Nabc​

代码提示

我们可以通过以下步骤来实现这个逻辑:

  1. 计算单个数的倍数个数

    • 计算 a 的倍数个数:countA = (r / a) - ((l - 1) / a)
    • 计算 b 的倍数个数:countB = (r / b) - ((l - 1) / b)
    • 计算 c 的倍数个数:countC = (r / c) - ((l - 1) / c)
  2. 计算两个数的公倍数的个数

    • 计算 a 和 b 的公倍数个数:countAB = (r / lcm(a, b)) - ((l - 1) / lcm(a, b))
    • 计算 a 和 c 的公倍数个数:countAC = (r / lcm(a, c)) - ((l - 1) / lcm(a, c))
    • 计算 b 和 c 的公倍数个数:countBC = (r / lcm(b, c)) - ((l - 1) / lcm(b, c))
  3. 计算三个数的公倍数的个数

    • 计算 ab 和 c 的公倍数个数:countABC = (r / lcm(a, b, c)) - ((l - 1) / lcm(a, b, c))
  4. 使用容斥原理计算总数

    • 总数 = countA + countB + countC - countAB - countAC - countBC + countABC

代码框架

分别计算单个数的倍数个数、两个数的公倍数的个数、三个数的公倍数的个数以及使用容斥原理计算总数。

    //计算单个数的倍数个数
    int countA = (r / a) - ((l - 1) / a);
    int countB = (r / b) - ((l - 1) / b);
    int countC = (r / c) - ((l - 1) / c);

    // 计算两个数的公倍数的个数
    int countAB = (r / lcm(a, b)) - ((l - 1) / lcm(a, b));
    int countAC = (r / lcm(a, c)) - ((l - 1) / lcm(a, c));
    int countBC = (r / lcm(b, c)) - ((l - 1) / lcm(b, c));

    // 计算三个数的公倍数的个数
    int countABC = (r / lcm(a, b, c)) - ((l - 1) / lcm(a, b, c));

    // 使用容斥原理计算总数
    int totalCount = countA + countB + countC - countAB - countAC - countBC + countABC;

    return totalCount;

下面计算两个数的最小公倍数、三个数的最小公倍数、以及两个数的最大公约数

//计算两个数的最小公倍数
public static int lcm(int a, int b) {
    return a * (b / gcd(a, b));
}

// 计算三个数的最小公倍数
public static int lcm(int a, int b, int c) {
    return lcm(lcm(a, b), c);
}

// 计算两个数的最大公约数
public static int gcd(int a, int b) {
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

总结

  • 计算单个数的倍数个数:使用整除运算符 / 来计算。
  • 计算公倍数:使用 lcm 函数来计算两个数的最小公倍数,并递归计算三个数的最小公倍数。
  • 使用容斥原理:通过加减不同的计数来避免重复计算。