题目大意:有一个序列,大小为m,里面有m个不超过20的非负数,各不相同。要求在1-n中有多少个能被m个数中任意一个数整除。
题目思路:简单的容斥原理应用。就不说了直接上代码。
有两种方法,一种是DFS,一种是直接位元素枚举暴力(study from zhixiaoli)
DFS:(速度较快)
#include<iostream> #include<algorithm> using namespace std; long long a[15]; int n, m; int gcd(int a, int b) { if (b == 0) return 0; int c = a%b; while (c) { a = b; b = c; c = a%b; } return b; } long long lcm(long long a, long long b) { long long c = gcd(a, b); if (c == 0) return 0; return a*b / c; } int gao(int x) { if (x == 0) return 0; return n / x; } int dfs(int i, bool flag, long long LCM) { long long ans = 0; long long mid = lcm(max(LCM,a[i]), min(LCM, a[i])); if (flag) ans += gao(mid); else ans -= gao(mid); for (int j = i + 1; j <= m; j++) ans += dfs(j, !flag, mid); return ans; } int main() { while (cin >> n >> m) { n--; for (int i = 1; i <= m; i++) cin >> a[i]; long long num = 0; for (int i = 1; i <= m; i++) num += dfs(i, 1, 1); cout << num << endl; } }
位元素枚举:(速度较慢)
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> using namespace std; #define ll long long int n, m; ll a[15]; ll GCD(ll x, ll y) { return y ? GCD(y, x%y) : x; } ll LCM(ll x, ll y) { return x / GCD(x, y)*y; } ll gao(int l, int&cnt) { ll res = 1; for (int i = cnt = 0; i < m; i++) { if (l&(1 << i)) { cnt++; res = LCM(res, a[i]); } } return res; } int main() { while (~scanf("%d%d", &n, &m)) { n--; int k=m; for (int i = 0; i < m; i++) { scanf("%lld", &a[i]); if (!a[i]) k = i; } if (k != m) { m--; swap(a[m], a[k]); } ll ans = 0; for (int i = 1; i < (1 << m); i++) { ll temp = gao(i, k); if (k & 1) ans += n / temp; else ans -= n / temp; } cout << ans << endl; } }
时间: 2024-10-05 05:25:49