用枚举子集 + __builtin_popcount 求 1~1000 中能被 2、3、5 整除的数的个数思路 因子:2、3、5,共 3 个,用3 位二进制表示子集 子集共 8 个:000 ~ 111 对每个子集:
用 __builtin_popcount(mask) 求二进制中 1 的个数,确定容斥符号:偶数个因子加,奇数个减 求子集对应数的最小公倍数 LCM
计算 1~1000 内能被 LCM 整除的数的个数:1000 / lcm
最后按容斥累加得到答案
C++ 代码cpp运行
#include <iostream>
#include <algorithm> // __gcd
using namespace std;
int lcm(int a, int b) {
return a / __gcd(a, b) * b;
}
int main() {
int d[] = {2, 3, 5};
int n = 3;
int ans = 0;
// 枚举所有子集 mask: 0 ~ 2^n - 1
for (int mask = 1; mask < (1 << n); mask++) {
int cnt = __builtin_popcount(mask); // 子集元素个数
int cur_lcm = 1;
for (int i = 0; i < n; i++) {
if (mask & (1 << i)) {
cur_lcm = lcm(cur_lcm, d[i]);
}
}
int num = 1000 / cur_lcm;
if (cnt % 2 == 1) ans += num;
else ans -= num;
}
cout << ans << endl;
return 0;
}
运行结果733
简要说明
mask = 001(1) → {2}
mask = 010(2) → {3}
mask = 100(4) → {5}
mask = 011(3) → {2,3} → LCM=6
mask = 101(5) → {2,5} → LCM=10
mask = 110(6) → {3,5} → LCM=15
mask = 111(7) → {2,3,5} → LCM=30
容斥公式:
$ (ans = \left\lfloor\frac{1000}{2}\right\rfloor+\left\lfloor\frac{1000}{3}\right\rfloor+\left\lfloor\frac{1000}{5}\right\rfloor -\left\lfloor\frac{1000}{6}\right\rfloor-\left\lfloor\frac{1000}{10}\right\rfloor-\left\lfloor\frac{1000}{15}\right\rfloor +\left\lfloor\frac{1000}{30}\right\rfloor) $
结果 = 733
挑战题目:765. 能被整除的数
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com