题意:求两个点(x,y,z)的连线不经过其他点有几个
解:即为求GCD(x,y,z)为1的点有几个
解一:因为x,y,z均在1~n内,所以可以用欧拉函数解出
解二:莫比乌斯反演
设f[n]为GCD(x,y,z)=n的个数
设F[b]为b|GCD(x,y,z)的个数,很明显F[b]=(n/i)*(n/i)*(n/i)
所以F[n]=sigema(b|n,f[b]);
f[n]=sigema(n|b,mu[n],F[n])
#include <stdio.h>
#include <string.h>
const int maxn=1000005;
int prime[maxn];
int num[maxn];
int mu[maxn];
void mobius()
{
memset(num,0,sizeof(num));
mu[1]=1;
int all=0;
for(int i=2;i<maxn;i++)
{
if(!num[i])
{
prime[all++]=i;
mu[i]=-1;
}
for(int j=0;j<all&&i*prime[j]<maxn;j++)
{
num[i*prime[j]]=1;
if(i%prime[j])
mu[i*prime[j]]=-mu[i];
else
{
mu[i*prime[j]]=0;
break;
}
}
}
return ;
}
int main()
{
int t;
int n;
long long sum;
mobius();
while(scanf("%d",&t)!=-1)
{
while(t--)
{
sum=3; //x,y,z轴
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
sum+=(long long)mu[i]*(n/i)*(n/i)*((n/i)+3); //在面上的点,所以+3
}
printf("%lld\n",sum);
}
}
return 0;
}