SPOJ VLATTICE Visible Lattice Points (莫比烏斯反演基礎題)
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
Date: | 2010-07-29 |
Time limit: | 1.368s |
Source limit: | 50000B |
Memory limit: | 1536MB |
Languages: | All except: NODEJS objc PERL 6 VB.net |
Resource: | own problem used for Indian ICPC training camp |
題目大意:求在(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\n", ans); } }