spoj VLATTICE Visible Lattice Points 莫比乌斯函数入门

题意:求正方体 n*n*n,固定其中一个点在(0,0,0) 问在正方体里又多少不同的直线。这个题的难点是如果排除掉重复的直线 例如 4,4,4
那么 2,2,2 和 4, 4,4 是相同的

推荐两个博客:http://blog.csdn.net/lixuepeng_001/article/details/50577932

http://blog.csdn.net/acdreamers/article/details/8542292

可以发现,gcd(x,y,z) 必定是为1的,不然的就会重复,那么如何统计这个数目而且不重复呢,假设F(t)函数代表gcd(x,y,z)=(k 的倍数)
因为这样理解,莫比乌斯函数就是特殊的容斥,就是排除倍数的影响,因为倍数会导致一些重复,现在要求的是

这里写图片描述

根据 这里写图片描述

因为枚举的是 因子 n/gcd(a,b)==1 的因子有n个 并且就是 n的全部所以枚举的是 1~n。
再用上 加速,就是利用 在一定的区间内,因子是一样的。所以是利用下界求上界。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn=1e6+7;  
bool vis[maxn];  
int prime[maxn],mu[maxn];  
int cnt;  
int sum[maxn];  

void Init(){  
    int N=maxn;  
    memset(prime,0,sizeof(prime));  
    memset(mu,0,sizeof(mu));  
    memset(vis,0,sizeof(vis));  
    mu[1] = 1;  
    cnt = 0;  
    for(int i=2; i<N; i++){  
        if(!vis[i]){  
            prime[cnt++] = i;  
            mu[i] = -1;  
        }  
        for(int j=0; j<cnt&&i*prime[j]<N; j++){  
            vis[i*prime[j]] = 1;  
            if(i%prime[j]) mu[i*prime[j]] = -mu[i];  
            else{  
                mu[i*prime[j]] = 0;  
                break;  
            }  
        }  
    }
    sum[0]=0;
    for(int i=1;i<N;i++)
        sum[i]=sum[i-1]+mu[i];
}

ll f(ll x1,ll x2)
{
    ll total=0;
    for(int i=1,next=0;i<=x1;i=next+1)
    {
        next=x1/(x1/i);
        //不同倍数,但是对于n来说//个数相同,所以可以加速,求出上界
        total=total+(1LL)*(sum[next]-sum[i-1])*(x1/i)*(x2/i);
//x/i 就是说有多少个这样的倍数
    }
    return total;
}

ll g(ll x1,ll x2,ll x3)
{
    ll total=0;
    for(int i=1,next=0;i<=x1;i=next+1)
    {
        next=x1/(x1/i);
        total=total+(1LL)*(sum[next]-sum[i-1])*(x1/i)*(x2/i)*(x3/i);
    }
    return total;
}


int main()
{
    int t;
    cin>>t;
    Init();
    while(t--){
        long long n;
        scanf("%lld",&n);
        long long ans=3+3*f(n,n)+g(n,n,n);
        cout<<ans<<endl;
    }
}
posted @ 2017-09-19 21:18  黑码的博客  阅读(121)  评论(0编辑  收藏  举报