小C的数字倍数问题

问题描述

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


测试样例

样例1:

输入:a = 2,b = 3,c = 4,l = 1,r = 10
输出:7

样例2:

输入:a = 5,b = 7,c = 11,l = 15,r = 100
输出:34

样例3:

输入:a = 1,b = 1,c = 1,l = 1,r = 1000
输出:1000

解题思路

  1. 直接计数法

    • 遍历区间 [l, r] 内的每一个数,检查它是否是 ab 或 c 的倍数。
    • 这种方法的时间复杂度是 O(n),其中 n = r - l + 1。对于较大的区间,这种方法可能会比较慢。
  2. 数学方法

    • 计算区间 [l, r] 内 a 的倍数的个数。
    • 计算区间 [l, r] 内 b 的倍数的个数。
    • 计算区间 [l, r] 内 c 的倍数的个数。
    • 使用容斥原理来避免重复计数:
      • 计算 a 和 b 的公倍数的个数。
      • 计算 a 和 c 的公倍数的个数。
      • 计算 b 和 c 的公倍数的个数。
      • 计算 ab 和 c 的公倍数的个数。
    • 最终结果是上述所有计数的总和,减去重复计数的部分。

数据结构选择

  • 不需要额外的数据结构,只需要基本的数学运算。

算法步骤

  1. 计算 abc 在区间 [l, r] 内的倍数个数。
  2. 计算 a 和 ba 和 cb 和 c 的公倍数个数。
  3. 计算 ab 和 c 的公倍数个数。
  4. 使用容斥原理计算最终结果。

代码实现1:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // for std::gcd
#include <numeric>   // for std::gcd in C++17

using namespace std;

// 计算在区间 [l, r] 内 n 的倍数的个数
int countMultiples(int n, int l, int r) {
    return r / n - (l - 1) / n;
}

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

int solution(int a, int b, int c, int l, int r) {
    // 计算 a 的倍数个数
    int countA = countMultiples(a, l, r);
    
    // 计算 b 的倍数个数
    int countB = countMultiples(b, l, r);
    
    // 计算 c 的倍数个数
    int countC = countMultiples(c, l, r);
    
    // 计算 a 和 b 的公倍数个数
    int countAB = countMultiples(lcm(a, b), l, r);
    
    // 计算 a 和 c 的公倍数个数
    int countAC = countMultiples(lcm(a, c), l, r);
    
    // 计算 b 和 c 的公倍数个数
    int countBC = countMultiples(lcm(b, c), l, r);
    
    // 计算 a、b 和 c 的公倍数个数
    int countABC = countMultiples(lcm(lcm(a, b), c), l, r);
    
    // 使用容斥原理计算最终结果
    int result = countA + countB + countC - countAB - countAC - countBC + countABC;
    
    return result;
}

int main() {
    std::cout << (solution(2, 3, 4, 1, 10) == 7) << std::endl;
    std::cout << (solution(5, 7, 11, 15, 100) == 34) << std::endl;
    std::cout << (solution(1, 1, 1, 1, 1000) == 1000) << std::endl;
    return 0;
}

代码实现2:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // for std::abs

using namespace std;

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

// 计算在区间 [l, r] 内 n 的倍数的个数
int countMultiples(int n, int l, int r) {
    return r / n - (l - 1) / n;
}

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

int solution(int a, int b, int c, int l, int r) {
    // 计算 a 的倍数个数
    int countA = countMultiples(a, l, r);
    
    // 计算 b 的倍数个数
    int countB = countMultiples(b, l, r);
    
    // 计算 c 的倍数个数
    int countC = countMultiples(c, l, r);
    
    // 计算 a 和 b 的公倍数个数
    int countAB = countMultiples(lcm(a, b), l, r);
    
    // 计算 a 和 c 的公倍数个数
    int countAC = countMultiples(lcm(a, c), l, r);
    
    // 计算 b 和 c 的公倍数个数
    int countBC = countMultiples(lcm(b, c), l, r);
    
    // 计算 a、b 和 c 的公倍数个数
    int countABC = countMultiples(lcm(lcm(a, b), c), l, r);
    
    // 使用容斥原理计算最终结果
    int result = countA + countB + countC - countAB - countAC - countBC + countABC;
    
    return result;
}

int main() {
    std::cout << (solution(2, 3, 4, 1, 10) == 7) << std::endl;
    std::cout << (solution(5, 7, 11, 15, 100) == 34) << std::endl;
    std::cout << (solution(1, 1, 1, 1, 1000) == 1000) << std::endl;
    return 0;
}

解释

  1. gcd 函数

    • 使用欧几里得算法计算两个数的最大公约数。
    • 算法步骤:
      • 当 b 不为 0 时,将 b 赋值给 a,将 a % b 赋值给 b,重复此过程。
      • 当 b 为 0 时,a 即为最大公约数。
  2. lcm 函数

    • 使用 gcd 函数计算最小公倍数。
    • 公式为:lcm(a, b) = abs(a * b) / gcd(a, b)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值