您的位置:首页 > 其它

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

2016-12-06 20:48 295 查看

传送门: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;
}

 

  

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: