Description
给定n和m个数,求1~n中不被这m个数中任意一个数整除的数的个数
Solution
容斥原理
假设现在求1~n中被这a,b中任意一个数整除的数的个数
这个区间中能被a整除的数的个数是$lfloorfrac{n}{a} floor$
同理,能被b整除的数的个数是$lfloorfrac{n}{b} floor$
那么被a,b两个数中任意一个数整除的数有$lfloorfrac{n}{a} floor+lfloorfrac{n}{b} floor-lfloorfrac{n}{lcm(a,b)} floor$
这是因为a,b的公倍数会被多算一次,a,b的公倍数一共有$lfloorfrac{n}{lcm(a,b)} floor$个
推广到m个数上
被这m个数中的任意一个数整数的数的个数就是
被任意一个数整除的个数-被任意两个数的公倍数整除的个数+被任意三个数的公倍数整除的数的个数-……
那么我们枚举一下,然后利用容斥原理就可以了
最后用总数减去结果就是答案了
时间复杂度$O(2^{m} imes m)$
Code
#include <bits/stdc++.h> namespace shl { typedef long long ll; int a[20]; int n, m; ll ans; ll gcd(ll a, ll b) { if (!b) return a; return gcd(b, a % b); } ll lcm(ll a, ll b) { return a / gcd(a, b) * b; } int main() { while (~scanf("%d%d", &n, &m)) { memset(a, 0, sizeof(a)); ans = n; int num; for (register int i = 1; i <= m; ++i) scanf("%d", &a[i]); int full = 1 << m; for (register int i = 1; i < full; ++i) { num = 0; ll sum = 1ll; for (register int j = 0; j < m; ++j) if (i & (1 << j)) { num++; sum = lcm(sum, a[j + 1]); } if (num & 1) ans -= n / sum; else ans += n / sum; } printf("%lld ", ans); } return 0; } }; int main() { shl :: main(); return 0; }
$lfloorfrac{n}{a} floor$