【莫比乌斯反演】[SPOJ VLATTICE]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.
大概就是给你个边长为n的立方体其中含有
题目分析首先可以把整个立体图形划分成三种第一种在经过(0,0,0)以下称为
- 经过
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;
}