因为数据比较小,我的方法非常蠢。。
直接枚举M个数的集合的子集,记为s
然后球子集s里的数的最小公约数,并统计里面的数量,记为cnt
然后看小于n的数中,有多少个最小公约数的倍数,记为t
看cnt的奇偶性,奇数就加t,偶数就减t(容斥定理)
然后就做完了,因为数据小,对于这题复杂度足够了
#include<map> #include<set> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<string> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #include<functional> using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MX = 1e2 + 5; LL n; int S[MX], m; LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } LL lcm(LL a, LL b) { return a / gcd(a, b) * b; } LL solve(LL x) { return (n - 1) / x; } int main() { //freopen("input.txt", "r", stdin); while(~scanf("%I64d%d", &n, &m)) { int tot = 0, t; for(int i = 0; i < m; i++) { scanf("%d", &t); if(t) S[tot++] = t; } m = tot; LL ans = 0; for(int s = 1; s < (1 << m); s++) { int cnt = 0, sign = false; LL x = 1; for(int i = 0; i < m; i++) { if(s >> i & 1) { x = lcm(x, S[i]); if(x >= n) { sign = true; break; } cnt++; } } if(sign) continue; ans += solve(x) * (cnt % 2 ? 1 : -1); } printf("%I64d\n", ans); } return 0; }