题目描述:
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.
大概就是给你个边长为n的立方体其中含有
(n+1)3
个格点,那么如果当前位于(0,0,0)请问可以直接看到的格点有多少个?
题目分析首先可以把整个立体图形划分成三种第一种在经过(0,0,0)以下称为 A 点
- 经过
A 的棱上的- 经过 A 的面但是不包含1的
在
A 的体内的但是不包含1、2的显然就是把整个图形分成了三个(n*n)的面和一个(n*n*n)的立方体和三条棱,对于三条棱来说答案一定是3
对于n*n的平面来说如果一个点的横坐标和纵坐标互质那么这样的点的个数*3就是我们需要的三个面的点数的贡献首先 F(i)=∑i|df(d)=⌊ni⌋2 这里 F(i) 表示在 i|gcd(a,b) 这样的数对的个数 f(i) 表示 i=gcd(a,b) 的个数那么刚刚的式子显然成立,根据莫比乌斯反演可以得到 f(i)=∑i|dμ(di)F(d)=∑i|dμ(di)⌊nd⌋2 那么显然此时i=1因为我们要求的就是(a,b)互质对的个数,那么另i=1就可以开始写程序了注意到 ⌊nd⌋ 的取值范围有 n−−√ 个那么可以稍微剪枝一下,同理可以得到另一个对于(a,b,c)来说两两互质的对数 g(n)=∑i|dμ(di)⌊nd⌋3 那么答案就是Ans=g(n)+3×f(n)+3#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; const long long MAXN = 1000000; bool notprime[MAXN+10]; int prime[MAXN+10], mu[MAXN+10], sum[MAXN+10]; long long GetAns(long long u){ long long ret1 = 0, ret2 = 0; for(int i=1;i<=u;i++){ int last = (u/(u/i)); ret1 += (sum[last] - sum[i-1]) * (u/i) * (u/i) * (u/i); ret2 += (sum[last] - sum[i-1]) * (u/i) * (u/i); i = last; } return ret1 + ret2*3 + 3; } void Init(long long Max){ mu[1] = 1; long long tmp; for(long long i=2;i<=Max;i++){ if(!notprime[i]){ mu[i] = -1; prime[++prime[0]] = i; } for(int j=1;j<=prime[0]&&(tmp=prime[j]*i)<=Max;j++){ notprime[tmp] = true; if(i%prime[j] == 0){ mu[tmp] = 0; break; } mu[tmp] = -mu[i]; } } for(int i=1;i<=Max;i++) sum[i] = sum[i-1] + mu[i]; } int main(){ int T; Init(1000000); cin>>T; while(T--){ long long n; cin>>n; cout<<GetAns(n)<<endl; } return 0; }