SPOJ--VLATTICE(莫比乌斯反演)

2016-04-18 22:59:24

题意:一个从(0,0,0)到(N,N,N)的晶格,问从原点能看到多少晶格,即问 gcd(x,y,z)=1的对数(0 <= x , y , z <= N)

思路:典型的mobius,显然需要 gcd(x,y,z)=m,以及 d|gcd(x,y,z) 两种定义,设 F(d) = Sigma(f(m)) ,(d|m); f(m) = number of gcd(x,y,z)=m

  所以 f(m) = Sigma(mu(m/d) * F(m)) ,(d|m),预处理mu数组,然后O(n)处理解。

  注意考虑 (1,0,0) , (0,1,0) , (0,0,1) 三个点,以及 x=0,y=0,z=0, 时的三个平面上的解。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <time.h>
 5 #include <math.h>
 6 #include <vector>
 7 #include <map>
 8 #include <set>
 9 #include <stack>
10 #include <queue>
11 #include <string>
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 
16 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
17 #define MEM(a,b) memset(a,b,sizeof(a))
18 #define MP(a,b) make_pair(a,b)
19 #define PB push_back
20 
21 typedef long long ll;
22 typedef pair<int,int> pii;
23 const double eps = 1e-8;
24 const int INF = (1 << 30) - 1;
25 const int MAXN = 1000010;
26 
27 int T,N;
28 int mu[MAXN];
29 int vis[MAXN],prime[MAXN],pcnt;
30 
31 void Mu_pre(){
32     memset(vis,0,sizeof(vis));
33     mu[1] = 1;
34     pcnt = 0;
35     int top = 1000000;
36     for(int i = 2; i <= top; ++i){
37         if(!vis[i]){
38             prime[++pcnt] = i;
39             mu[i] = -1;
40         }
41         for(int j = 1; j <= pcnt && i * prime[j] <= top; ++j){
42             vis[i * prime[j]] = 1;
43             if(i % prime[j]) mu[i * prime[j]] = -mu[i];
44             else{
45                 mu[i * prime[j]] = 0;
46                 break;
47             }
48         }
49     }
50 }
51 
52 int main(){
53     Mu_pre();
54     scanf("%d",&T);
55     while(T--){
56         scanf("%d",&N);
57         ll ans = 3;
58         for(int i = 1; i <= N; ++i) ans += 1ll * mu[i] * (N / i) * (N / i) * (N/ i + 3);
59         printf("%lld\n",ans);
60     }
61     return 0;
62 }

 

posted @ 2016-04-18 23:04  Naturain  阅读(150)  评论(0)    收藏  举报