[hdu1695] GCD【莫比乌斯反演】

传送门: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\n", ans);
	}
	return 0;
}

 

  

 

posted @ 2016-12-06 20:48  ciao_sora  阅读(149)  评论(0编辑  收藏  举报