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

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

明显,当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;
}

  

posted @ 2015-03-11 23:26  雪溯  阅读(195)  评论(0编辑  收藏  举报