Spoj 7001 Visible Lattice Points 莫比乌斯,分块

 
Time Limit: 1368MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu

 Status

Description

Consider a N*N*N lattice. One corner is at (0,0,0) and the opposite one is at (N,N,N). How many lattice points are visible from corner at (0,0,0) ? A point X is visible from point Y iff no other lattice point lies on the segment joining X and Y. 
 
Input : 
The first line contains the number of test cases T. The next T lines contain an interger N 
 
Output : 
Output T lines, one corresponding to each test case. 
 
Sample Input : 




 
Sample Output : 

19 
175 
 
Constraints : 
T <= 50 
1 <= N <= 1000000

Hint

 
题意:在一个边长为n的正方体内,从原点出发能够接触多少个点。
 
题解:
莫比乌斯反演。
首先,我们要把答案分三类讨论:
1, 坐标轴上的三个点可以看见(1,0,0)和(0,1,0)和(0,0,1)。
2, 与原点相邻的三个表面的点。在三个表面各反演一次,加起来即可。
3, 在三维空间中反演一次即可。
答案为三种情况的和。
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define MAXN 1000010
 4 #define LL long long
 5 int mu[MAXN+10],prime[80010],qz[MAXN+10],tot;
 6 bitset<MAXN+10> vis;
 7 int read()
 8 {
 9     int s=0,fh=1;char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
11     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
12     return s*fh;
13 }
14 void getmu()
15 {
16     int i,j;
17     mu[1]=1;tot=0;
18     for(i=2;i<=MAXN;i++)
19     {
20         if(vis[i]==0)
21         {
22             prime[++tot]=i;
23             mu[i]=-1;
24         }
25         for(j=1;j<=tot&&prime[j]*i<=MAXN;j++)
26         {
27             vis[prime[j]*i]=1;
28             if(i%prime[j]==0)
29             {
30                 mu[prime[j]*i]=0;
31                 break;
32             }
33             mu[prime[j]*i]=-mu[i];
34         }
35     }
36 }
37 void Qz()
38 {
39     for(int i=1;i<=MAXN;i++)qz[i]=qz[i-1]+mu[i];
40 }
41 LL calc2(int n)//计算平面上的个数.
42 {
43     int d,pos;
44     LL sum=0;
45     for(d=1;d<=n;d=pos+1)
46     {
47         pos=n/(n/d);
48         sum+=(LL)(qz[pos]-qz[d-1])*(n/d)*(n/d);
49     }
50     return sum;
51 }
52 LL calc3(int n)//计算空间里的个数.
53 {
54     int d,pos;
55     LL sum=0;
56     for(d=1;d<=n;d=pos+1)
57     {
58         pos=n/(n/d);
59         sum+=(LL)(qz[pos]-qz[d-1])*(n/d)*(n/d)*(n/d);
60     }
61     return sum;
62 }
63 int main()
64 {
65     int N,T;
66     T=read();
67     getmu();
68     Qz();
69     while(T--)
70     {
71         N=read();
72         printf("%lld\n",calc3(N)+calc2(N)*3+3);
73     }
74     fclose(stdin);
75     fclose(stdout);
76     return 0;
77 }
View Code

 

 

posted @ 2016-03-16 20:44  微弱的世界  阅读(161)  评论(0编辑  收藏  举报