UVa 11014 (莫比乌斯反演) Make a Crystal

这个题是根据某个二维平面的题改编过来的。

首先把问题转化一下, 就是你站在原点(0, 0, 0)能看到多少格点。

答案分为三个部分:

  1. 八个象限里的格点,即 gcd(x, y, z) = 1,且xyz均不为0. 可以先假设xyz都是整数,然后将所求的答案乘8
  2. 12个四分之一平面中的点,可以先算(x, y, 0)(x > 0, y > 0)这样的点的个数,然后乘12
  3. 坐标轴上距原点距离为1的6个点

三维对应的莫比乌斯公式就是:

在这道题里面就是 X = Y = Z = N / 2

这道题用容斥原理或者欧拉函数也可以做,但是还是莫比乌斯反演最好写最快了。

 1 #include <iostream>

 2 #include <cstdio>

 3 #include <algorithm>

 4 using namespace std;

 5 typedef long long LL;

 6 

 7 const int maxn = 200000;

 8 int prime[maxn + 10], mu[maxn + 10];

 9 bool vis[maxn + 10];

10 

11 void Mobius()

12 {

13     mu[1] = 1;

14     int cnt = 0;

15     for(int i = 2; i <= maxn; i++)

16     {

17         if(!vis[i]) { mu[i] = -1; prime[cnt++] = i; }

18         for(int j = 0; j < cnt && (LL)i*prime[j] <= maxn; j++)

19         {

20             vis[i * prime[j]] = 1;

21             if(i % prime[j] != 0) mu[i*prime[j]] = -mu[i];

22             else { mu[i*prime[j]] = 0; break; }

23         }

24     }

25 

26     for(int i = 2; i <= maxn; i++) mu[i] += mu[i - 1];

27 }

28 

29 int main()

30 {

31     Mobius();

32 

33     int n, kase = 0;

34     while(scanf("%d", &n) == 1 && n)

35     {

36         n /= 2;

37         LL ans = 6;

38         for(int i = 1, j; i <= n; i = j + 1)

39         {

40             int t = n / i;

41             j = n / t;

42             ans += ((LL)t*t*t*8 + (LL)t*t*12) * (mu[j] - mu[i - 1]);

43         }

44         printf("Crystal %d: %lld\n", ++kase, ans);

45     }

46 

47     return 0;

48 }
代码君

 

你可能感兴趣的:(Make)