【莫比乌斯反演】[SPOJ-VLATTICE]Visible Lattice Points

题目
题目大意就是求在一个边长为N的正方体内,你站在(0,0,0)所能看到的所有点。
分析:这道题,我们可以分成三类来讨论.
第一类:坐标轴上的点
我们无论如何只能看见3个。
第二类:与原点相邻的三个表面的点
我们考虑其中一个表面,当且仅当在该点表面的坐标(x,y)满足gcd(x,y)=1时,可见。问题就转化为求1<=x,y<=n时,gcd(x,y)=1的对数,做法参加我的这篇博客。将所得答案*3即可。
第三类:其余情况
当且仅当(x,y,z),gcd(x,y,z)=1时可见。根据求二元组的F(i),f(i)推广,可得

F(i)=n/i3=i|df(d)=>f(i)=i|dμ(d/i)F(d)
然后求出f(1)即可。
三类情况的答案之和即为最终答案。

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 1000000
typedef long long LL;
int T,n,p[MAXN+10],mu[MAXN+10],sum[MAXN+10],pcnt;
bool f[MAXN+10];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void prepare(){
    int i,j;
    mu[1]=sum[1]=1;
    for(i=2;i<=MAXN;i++){
        if(!f[i])
            p[++pcnt]=i,mu[i]=-1;
        for(j=1;p[j]*i<=MAXN;j++){
            f[p[j]*i]=1;
            if(i%p[j]==0){
                mu[p[j]*i]=0;
                break;
            }
            mu[p[j]*i]=-mu[i];
        }
        sum[i]=sum[i-1]+mu[i];
    }
}
LL cal2(int n){
    int i,last;
    LL ret=0;
    for(i=1;i<=n;i=last+1){
        last=n/(n/i);
        ret+=1ll*(sum[last]-sum[i-1])*(n/i)*(n/i);
    }
    return ret;
}
LL cal3(int n){
    int i,last;
    LL ret=0;
    for(i=1;i<=n;i=last+1){
        last=n/(n/i);
        ret+=1ll*(sum[last]-sum[i-1])*(n/i)*(n/i)*(n/i);
    }
    return ret;
}
int main()
{
    Read(T);
    prepare();
    while(T--){
        Read(n);
        printf("%lld\n",cal3(n)+cal2(n)*3+3);
    }
}
posted @ 2016-01-26 22:32  outer_form  阅读(143)  评论(0编辑  收藏  举报