刷题打卡 | 豆包MarsCode AI 刷题

98 阅读2分钟

小C的数字倍数问题

题目要求我们在给定区间 [l,r][l, r] 中找到所有是 aa 的倍数、bb 的倍数或 cc 的倍数的整数个数。

分析 首先,假设区间内有一些数能被 aa 整除,称之为 “aa 的倍数”,类似地定义 “bb 的倍数” 和 “cc 的倍数”。我们可以通过求出各个倍数的数量并进行适当的加减来避免重复计数。

求解思路 直接计数的缺陷: 如果我们分别计算出 [l,r][l, r] 区间内 aa 的倍数、bb 的倍数、cc 的倍数的个数,再将它们加起来,会出现重复计数。例如,一个数可能同时是 aabb 的倍数。

集合包含原理: 通过集合包含原理,我们可以消除重复计数的问题:

单独计算 aa 的倍数、bb 的倍数、cc 的倍数的数量。 减去 [l,r][l, r] 内同时是 aabb 倍数的数量(即 lcm(a,b)lcm(a, b) 的倍数),以及其他成对倍数的情况。 加回 [l,r][l, r] 内同时是 aabbcc 三者倍数的数量(即 lcm(a,b,c)lcm(a, b, c) 的倍数),因为它们被减去了三次。 区间 [1,n][1, n] 内倍数的计数公式:

计算 xx 的倍数数量,区间 [1,n][1, n] 内能被 xx 整除的数有 n/xn / x 个。 利用上面的公式,我们可以计算出在 rrl1l - 1 中分别满足条件的数量,再相减即可得出 [l,r][l, r] 的结果。 解题步骤 编写 lcmlcm 函数,计算两个数的最小公倍数。 利用集合包含原理,计算 [1,r][1, r] 区间内满足条件的数量,再计算 [1,l1][1, l-1] 区间内满足条件的数量,两者相减即可。

#include <bits/stdc++.h>
using namespace std;

int lcm(int x, int y) {
    return x * y / __gcd(x, y);
}

int solution(int a, int b, int c, int l, int r) {
    --l;
    int lcm_ab = lcm(a, b);
    int lcm_ac = lcm(a, c);
    int lcm_bc = lcm(b, c);
    int lcm_abc = lcm(lcm_ab, c);
    int count_r = r / a + r / b + r / c - r / lcm_ab - r / lcm_ac - r / lcm_bc + r / lcm_abc;
    int count_l = l / a + l / b + l / c - l / lcm_ab - l / lcm_ac - l / lcm_bc + l / lcm_abc;
    return count_r - count_l;
}

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;
}