您的位置:首页 > 其它

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

2016-01-26 22:32 302 查看
题目

题目大意就是求在一个边长为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/i⌋3=∑i|df(d)=>f(i)=∑i|dμ(d/i)F(d)F(i)=\lfloor{n/i}\rfloor^3=\sum_{i|d}f(d)=>f(i)=\sum_{i|d}\mu(d/i)F(d)然后求出f(1)即可。

三类情况的答案之和即为最终答案。

[code]#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);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: