SPOJ VLATTICE Visible Lattice Points 初入莫比乌斯

来源:互联网 发布:短网址赚钱源码 编辑:程序博客网 时间:2024/04/27 20:58

题意:求两个点(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;}


1 0