回忆 HDU 4135 经典题 Co-Prime 求[a,b]区间与给定素数p互质的个数。 将p质因数分解后容斥即可。 原理就是质因数的倍数就是与p不互素的数。
此题的写法:
ll p[maxn]; int cnt; ll n; void init(ll m) { for (int i = 2; i * i <= m; i++) { if (m % i == 0) { p[cnt++] = i; while (m % i == 0) m /= i; } } if (m > 1) p[cnt++] = m; } ll solve(ll x) { ll len = 1ll << cnt; ll ans = 0; for (ll i = 1; i < len; i++) { int f = 0; ll tmp = 1; for (ll j = 0; j < cnt; j++) { if (i & (1ll << j)) { f++; tmp *= p[j]; } } if (f & 1) ans += x / tmp; else ans -= x/ tmp; } return ans; } int main() { int T; ll a, b; scanf("%d", &T); int kase = 1; while (T--) { cnt = 0; scanf("%lld%lld%lld", &a, &b, &n); init(n); printf("Case #%d: %lld ", kase++, (b - a + 1) - (solve(b) - solve(a - 1))); } return 0; }
而HDU4407 这题问的是区间的互质的数的和。 其实是差不多的,只不过把个数变成求和。对于分解质因数后的每个质数p,其倍数p,2p,3p.....都是与给定的数不互质的数,容斥即可。
注意 对于询问1 可以开一个map表示 a->b 的关系。每次for一遍就行。
ll a[maxn]; int cnt; ll n, m; map<ll, ll> mp; ll x, y, z; ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } void init(ll x) { cnt = 0; for (ll i = 2; i * i <= x; i++) { if (x % i == 0) { a[cnt++] = i; while (x % i == 0) x /= i; } } if (x > 1) a[cnt++] = x; } ll solve(ll x) { ll ans = 0; for (ll i = 1; i < (1ll << cnt); i++) { ll sum = 1; int byte = 0; for (int j = 0; j < cnt; j++) { if (i & (1ll << j)) { byte++; sum *= a[j]; } } if (byte & 1) ans += (sum + x / sum * sum) * (x / sum )/2; else ans -= (sum + x / sum * sum) * (x / sum) /2; } return ans; } int main() { int T; scanf("%d", &T); int k; while (T--) { mp.clear(); scanf("%lld%lld", &n, &m); for (int i = 0; i < m; i++) { scanf("%d", &k); if (k == 2) scanf("%lld%lld", &x, &y), mp[x] = y; else { scanf("%lld%lld%lld", &x, &y, &z); init(z); ll res = (y - x + 1)* (x + y) / 2 - (solve(y) - solve(x - 1)); for (auto it = mp.begin(); it != mp.end(); it++) { if (it->first >= x && it->first <= y) { if (gcd(it->first, z) == 1) res -= it->first; if (gcd(it->second, z) == 1) res += it->second; } } printf("%lld ", res); } } } }