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
题意:
可以说此题是Visible Trees HDU2841(有详解)这道题目的改编,原题是求一个平面上即二维的,能看到多少并且是从(1,1)-(m,n),但是上面那道题我当时使用容斥做的,这道题则变成了三维的,问能看到多少点
分析:
如果大家先看看上面说的那道题目的话,就会明白,实际上是让我们找gcd(a,b,c) = 1的点有多少个,只要满足gcd(a,b,c) = 1就能看见
那么这道题就又和题目GCD hdu1695实质上也是求gcd(a,b) = 1的个数,而这道题我是用莫比乌斯反演做的
因此对于一般情况而言直接利用莫比乌斯反演可做
但是需要注意特殊情况,即在xyz直角坐标系中,在三个平面上时其实相当于是二维的,即有一个坐标为0,这样共有三种情况即在xy面,yz面,xz面,因此求处二维的乘3。
另一种特殊情况是在坐标轴上即有两个坐标为0,这样每个轴上就只能看到三个点,所以我们可以初始化sum=3,然后开始后面的累加
code:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
int prime[maxn],cnt;
int mu[maxn];
bool vis[maxn];
void init(){
int N = maxn;
memset(prime,0,sizeof(prime));
memset(mu,0,sizeof(mu));
memset(vis,0,sizeof(vis));
mu[1] = 1;
cnt = 0;
for(int i = 2; i < N; i++){
if(!vis[i]){
prime[cnt++] = i;
mu[i] = -1;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++){
vis[i*prime[j]] = 1;
if(i % prime[j]) mu[i*prime[j]] = -mu[i];
else{
mu[i*prime[j]] = 0;
break;
}
}
}
}
int main(){
init();
int T;
scanf("%d",&T);
while(T--){
ll n;
scanf("%lld",&n);
ll sum = 3;//在坐标轴上x,y,z
for(ll i = 1; i <= n; i++){
sum += mu[i] * (n / i) * (n / i) * (n / i + 3);
//(n / i) * (n / i) * 3 相当于在面上的和
//(n / i) * (n / i) *(n / i)相当于一般情况
}
printf("%lld\n",sum);
}
return 0;
}