传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1695
先把题目转化为求一个数在区间[1, b / k],另一个数在区间[1, d / k]时,这两个数互质的对数(是number of pairs,不是logarithm,下同)。
纠结了半天,一直在想莫比乌斯反演的公式不是“F(n) = sigma d|n f(d) => f(n) = sigma d|n mu(d) * F(n / d)”吗?没想到还有另外一种形式“F(n) = sigma n|d f(d) => f(n) = sigma n|d mu(d / n) * F(d)”!这就是为什么“对于一些函数f(n),如果我们很难直接求出它的值,而容易求出倍数和或约数和F(n),那么我们可以通过莫比乌斯反演来求得f(n)的值”。
#include <cstdio> const int maxn = 100005; int T, a, b, c, d, k, mu[maxn], prime[maxn], tot, tem; bool book[maxn]; long long ans; inline long long F(int mn, int mx) { return (long long)((mx << 1 | 1) - mn) * (long long)mn >> 1; } int main(void) { mu[1] = 1; for (int i = 2; i < maxn; ++i) { if (!book[i]) { prime[tot++] = i; mu[i] = -1; } for (int j = 0; j < tot; ++j) { if (i * prime[j] > maxn) { break; } book[i * prime[j]] = true; if (i % prime[j] == 0) { break; } mu[i * prime[j]] = -mu[i]; } } scanf("%d", &T); for (int kase = 1; kase <= T; ++kase) { printf("Case %d: ", kase); ans = 0; scanf("%d%d%d%d%d", &a, &b, &c, &d, &k); if (!k) { puts("0"); continue; } b /= k; d /= k; if (b > d) { tem = b; b = d; d = tem; } for (int i = 1; i <= b; ++i) { ans += mu[i] * F(b / i, d / i); } printf("%lld ", ans); } return 0; }