Visible Lattice Points
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 :
3
1
2
5
Sample Output :
7
19
175
Constraints :
T <= 50
1 <= N <= 1000000
Added by: | Varun Jalan |
Date: | 2010-07-29 |
Time limit: | 1.368s |
Source limit: | 50000B |
Memory limit: | 1536MB |
Cluster: | Cube (Intel Pentium G860 3GHz) |
Languages: | All except: NODEJS objc PERL 6 VB.net |
Resource: | own problem used for Indian ICPC training camp |
题目链接:http://www.spoj.com/problems/VLATTICE/en/
题目大意:求在(0,0,0)到(n,n,n)这个立方体里从(0,0,0)能看到多少个点
题目分析:(2,2,2)就看不到。由于被(1,1,1)挡住了。做过能量採集的都知道,就是求gcd(a, b, c) = 1的组数。当中1 <= a, b, c <= n,裸的莫比乌斯反演题,注意两点。三个数轴上还有三点(0, 0, 1)。(0 ,1, 0),(1, 0, 0),另外xoy面。yoz面,xoz面。三个面上另一些点,这些都要单独算,然后再加上立方体中不包含轴和面的点,分块求和优化10ms解决
#include <cstdio> #include <algorithm> #define ll long long using namespace std; int const MAX = 1000005; int mob[MAX], p[MAX], sum[MAX]; bool noprime[MAX]; int Min(int a, int b, int c) { return min(a, min(b, c)); } void Mobius() { int pnum = 0; mob[1] = 1; sum[1] = 1; for(int i = 2; i < MAX; i++) { if(!noprime[i]) { p[pnum ++] = i; mob[i] = -1; } for(int j = 0; j < pnum && i * p[j] < MAX; j++) { noprime[i * p[j]] = true; if(i % p[j] == 0) { mob[i * p[j]] = 0; break; } mob[i * p[j]] = -mob[i]; } sum[i] = sum[i - 1] + mob[i]; } } ll cal(int l, int r) { if(l > r) swap(l, r); ll ans = 0; for(int i = 1, last = 0; i <= l; i = last + 1) { last = min(l / (l / i), r / (r / i)); ans += (ll) (l / i) * (r / i) * (sum[last] - sum[i - 1]); } return ans; } ll cal(int l, int m, int r) { if(l > r) swap(l, r); if(l > m) swap(l, m); ll ans = 0; for(int i = 1, last = 0; i <= l; i = last + 1) { last = Min(l / (l / i), m / (m / i), r / (r / i)); ans += (ll) (l / i) * (m / i) * (r / i) * (sum[last] - sum[i - 1]); } return ans; } int main() { Mobius(); int T; scanf("%d", &T); while(T --) { int n; scanf("%d", &n); ll ans = 3; ans += (ll) cal(n, n, n); ans += (ll) cal(n ,n) * 3; printf("%lld ", ans); } }