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 }
View Code

 

posted @ 2014-12-19 23:08  AOQNRMGYXLMV  阅读(482)  评论(0编辑  收藏  举报