SPOJ VLATTICE Visible Lattice Points 莫比乌斯反演 难度:3

http://www.spoj.com/problems/VLATTICE/

SPOJ VLATTICE Visible Lattice Points 莫比乌斯反演 难度:3SPOJ VLATTICE Visible Lattice Points 莫比乌斯反演 难度:3

明显,当gcd(x,y,z)=k,k!=1时,(x,y,z)被(x/k,y/k,z/k)遮挡,所以这道题要求的是gcd(x,y,z)==1的个数+{(x,y,0)|gcd(x,y)==1}的个数+3{(0,0,1),(0,1,0),(1,0,0)}

现在不去管最后的三个坐标轴上的点,

设f(i)=|{(x,y,0)|gcd(x,y)==i}|*3+|{(x,y,z)|gcd(x,y,z)==i}|,也就是不在坐标轴上且非0坐标值的最大公约数为n的个数,

设F(i)为由能被i整除的坐标值组成的不在坐标轴上的坐标的个数,则F(i)=n/i*n/i*(n/i+3),同时显然F(i)=sigma(b|n,f[i]),

由莫比乌斯反演,可得f(1)=sigma(mul(i)*F(i))

#include <cstdio>

#include <algorithm>

using namespace std;

const int maxn =1e6+2;

bool ifprime[maxn];

int mul[maxn];

int prime[maxn];

void moblus(){

        ifprime[2]=true;

        for(int i=3;i<maxn;i+=2)ifprime[i]=true;

        int pnum=0;

        mul[1]=1;

        for(int i=2;i<maxn;i++){

                if(ifprime[i]){

                        prime[pnum++]=i;

                        mul[i]=-1;

                }

                for(int j=0;j<pnum&&i*prime[j]<maxn;j++){

                        ifprime[i*prime[j]]=false;

                        if(i%prime[j]==0){

                                mul[i*prime[j]]=0;

                                break;

                        }

                        else {

                                mul[i*prime[j]]=-mul[i];

                        }

                }

        }

}

int main(){

        int T;

        moblus();

        scanf("%d",&T);

        while(T--){

                int n;

                scanf("%d",&n);

                long long ans=3;

                for(int i=1;i<=n;i++){

                                ans+=(long long)mul[i]*(n/i)*(n/i)*(n/i+3);

                }

                printf("%I64d\n",ans);

        }

        return 0;

}

  

你可能感兴趣的:(visible)