HDU 1695 (莫比乌斯反演) GCD
题意:
从区间[1, b]和[1, d]中分别选一个x, y,使得gcd(x, y) = k, 求满足条件的xy的对数(不区分xy的顺序)
分析:
虽然之前写过一个莫比乌斯反演的总结,可遇到这道题还是不知道怎么应用。
这里有关于莫比乌斯反演的知识,而且最后的例题中就有这道题并给出了公式的推导。
在最后的例题2中有个重要的结论:
1 #include <cstdio> 2 #include <algorithm> 3 typedef long long LL; 4 5 const int maxn = 1000000; 6 int mu[maxn + 10], vis[maxn + 10], prime[maxn], cnt; 7 8 void Mobius() 9 { 10 mu[1] = 1; 11 cnt = 0; 12 for(int i = 2; i <= maxn; ++i) 13 { 14 if(!vis[i]) 15 { 16 mu[i] = -1; 17 prime[cnt++] = i; 18 } 19 for(int j = 0; j < cnt && i*prime[j] <= maxn; ++j) 20 { 21 vis[i*prime[j]] = 1; 22 if(i % prime[j] != 0) mu[i*prime[j]] = -mu[i]; 23 else 24 { 25 mu[i*prime[j]] = 0; 26 break; 27 } 28 } 29 } 30 } 31 32 int main() 33 { 34 //freopen("1695in.txt", "r", stdin); 35 36 Mobius(); 37 int T; 38 scanf("%d", &T); 39 for(int kase = 1; kase <= T; ++kase) 40 { 41 int a, b, c, d, k; 42 scanf("%d%d%d%d%d", &a, &b, &c, &d, &k); 43 44 if(k == 0) 45 { 46 printf("Case %d: 0\n", kase); 47 continue; 48 } 49 50 b /= k, d /= k; 51 if(b > d) std::swap(b, d); 52 LL hehe = 0, haha = 0; 53 for(int i = 1; i <= b; ++i) 54 hehe += (LL)mu[i] * (b/i) * (d/i); 55 for(int i = 1; i <= b; ++i) 56 haha += (LL)mu[i] * (b/i) * (b/i); //因为题目不区分xy的顺序,所以要减去重复的部分 57 LL ans = hehe - haha/2; 58 59 printf("Case %d: %I64d\n", kase, ans); 60 } 61 62 return 0; 63 }