UVa 11014 (莫比乌斯反演) Make a Crystal
这个题是根据某个二维平面的题改编过来的。
首先把问题转化一下, 就是你站在原点(0, 0, 0)能看到多少格点。
答案分为三个部分:
- 八个象限里的格点,即 gcd(x, y, z) = 1,且xyz均不为0. 可以先假设xyz都是整数,然后将所求的答案乘8
- 12个四分之一平面中的点,可以先算(x, y, 0)(x > 0, y > 0)这样的点的个数,然后乘12
- 坐标轴上距原点距离为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 }