您的位置:首页 > 其它

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

2016-01-27 01:55 288 查看
题目描述:

Consider a N*N*N lattice. One corner is at (0,0,0) and the opposite one is at (N,N,N). How many lattice points are visible from corner at (0,0,0) ? A point X is visible from point Y iff no other lattice point lies on the segment joining X and Y.

大概就是给你个边长为n的立方体其中含有(n+1)3(n+1)^3个格点,那么如果当前位于(0,0,0)请问可以直接看到的格点有多少个?

题目分析首先可以把整个立体图形划分成三种第一种在经过(0,0,0)以下称为AA点

经过AA的棱上的

经过AA的面但是不包含1的

在AA的体内的但是不包含1、2的

显然就是把整个图形分成了三个(n*n)的面和一个(n*n*n)的立方体和三条棱,对于三条棱来说答案一定是3

对于n*n的平面来说如果一个点的横坐标和纵坐标互质那么这样的点的个数*3就是我们需要的三个面的点数的贡献首先F(i)=∑i|df(d)=⌊ni⌋2F(i)=\sum_{i|d}f(d)=\lfloor \frac{n}{i}\rfloor^2这里F(i)F(i)表示在i|gcd(a,b)i|gcd(a,b)这样的数对的个数f(i)f(i)表示i=gcd(a,b)i=gcd(a,b)的个数那么刚刚的式子显然成立,根据莫比乌斯反演可以得到f(i)=∑i|dμ(di)F(d)=∑i|dμ(di)⌊nd⌋2f(i)=\sum_{i|d}\mu(\frac{d}{i})F(d)=\sum_{i|d}\mu(\frac{d}{i})\lfloor \frac{n}{d}\rfloor^2那么显然此时i=1因为我们要求的就是(a,b)互质对的个数,那么另i=1就可以开始写程序了注意到⌊nd⌋\lfloor \frac{n}{d}\rfloor的取值范围有n−−√\sqrt{n}个那么可以稍微剪枝一下,同理可以得到另一个对于(a,b,c)来说两两互质的对数g(n)=∑i|dμ(di)⌊nd⌋3g(n)=\sum_{i|d}\mu(\frac{d}{i})\lfloor \frac{n}{d} \rfloor^3那么答案就是Ans=g(n)+3×f(n)+3Ans=g(n)+3\times f(n)+3

[code]#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const long long MAXN = 1000000;
bool notprime[MAXN+10];
int prime[MAXN+10], mu[MAXN+10], sum[MAXN+10];
long long GetAns(long long u){
    long long ret1 = 0, ret2 = 0;
    for(int i=1;i<=u;i++){
        int last = (u/(u/i));
        ret1 += (sum[last] - sum[i-1]) * (u/i) * (u/i) * (u/i);
        ret2 += (sum[last] - sum[i-1]) * (u/i) * (u/i);
        i = last;
    }
    return ret1 + ret2*3 + 3;
}
void Init(long long Max){
    mu[1] = 1;
    long long tmp;
    for(long long i=2;i<=Max;i++){
        if(!notprime[i]){
            mu[i] = -1;
            prime[++prime[0]] = i;
        }
        for(int j=1;j<=prime[0]&&(tmp=prime[j]*i)<=Max;j++){
            notprime[tmp] = true;
            if(i%prime[j] == 0){
                mu[tmp] = 0;
                break;
            }
            mu[tmp] = -mu[i];
        }
    }
    for(int i=1;i<=Max;i++)
        sum[i] = sum[i-1] + mu[i];
}
int main(){
    int T;
    Init(1000000);
    cin>>T;
    while(T--){
        long long n;
        cin>>n;
        cout<<GetAns(n)<<endl;
    }

    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: