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

 

你可能感兴趣的:(HDU)