SPOJ VLATTICE Visible Lattice Points (莫比乌斯反演基础题)

Visible Lattice Points


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.
 
Input :
The first line contains the number of test cases T. The next T lines contain an interger N
 
Output :
Output T lines, one corresponding to each test case.
 
Sample Input :
3
1
2
5
 
Sample Output :
7
19
175
 
Constraints :
T <= 50
1 <= N <= 1000000


Added by: Varun Jalan
Date: 2010-07-29
Time limit: 1.368s
Source limit: 50000B
Memory limit: 1536MB
Cluster: Cube (Intel Pentium G860 3GHz)
Languages: All except: NODEJS objc PERL 6 VB.net
Resource: own problem used for Indian ICPC training camp


题目链接:http://www.spoj.com/problems/VLATTICE/en/


题目大意:求在(0,0,0)到(n,n,n)这个立方体里从(0,0,0)能看到多少个点


题目分析:(2,2,2)就看不到。由于被(1,1,1)挡住了。做过能量採集的都知道,就是求gcd(a, b, c) = 1的组数。当中1 <= a, b, c <= n,裸的莫比乌斯反演题,注意两点。三个数轴上还有三点(0, 0, 1)。(0 ,1, 0),(1, 0, 0),另外xoy面。yoz面,xoz面。三个面上另一些点,这些都要单独算,然后再加上立方体中不包含轴和面的点,分块求和优化10ms解决

#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
int const MAX = 1000005;
int mob[MAX], p[MAX], sum[MAX];
bool noprime[MAX];

int Min(int a, int b, int c)
{
    return min(a, min(b, c));
}

void Mobius()
{
    int pnum = 0;
    mob[1] = 1;
    sum[1] = 1;
    for(int i = 2; i < MAX; i++)
    {
        if(!noprime[i])
        {
            p[pnum ++] = i;
            mob[i] = -1;
        }
        for(int j = 0; j < pnum && i * p[j] < MAX; j++)
        {
            noprime[i * p[j]] = true;
            if(i % p[j] == 0)
            {
                mob[i * p[j]] = 0;
                break;
            }
            mob[i * p[j]] = -mob[i];
        }
        sum[i] = sum[i - 1] + mob[i];
    }
}

ll cal(int l, int r)
{
    if(l > r)
        swap(l, r);
    ll ans = 0;
    for(int i = 1, last = 0; i <= l; i = last + 1)
    {
        last = min(l / (l / i), r / (r / i));
        ans += (ll) (l / i) * (r / i) * (sum[last] - sum[i - 1]);
    }
    return ans;
}

ll cal(int l, int m, int r)
{
    if(l > r)
        swap(l, r);
    if(l > m)
        swap(l, m);
    ll ans = 0;
    for(int i = 1, last = 0; i <= l; i = last + 1)
    {
        last = Min(l / (l / i), m / (m / i), r / (r / i));
        ans += (ll) (l / i) * (m / i) * (r / i) * (sum[last] - sum[i - 1]);
    }
    return ans;
}

int main()
{
    Mobius();
    int T;
    scanf("%d", &T);
    while(T --)
    {
        int n;
        scanf("%d", &n);
        ll ans = 3;
        ans += (ll) cal(n, n, n);
        ans += (ll) cal(n ,n) * 3;
        printf("%lld
", ans);
    }
}




原文地址:https://www.cnblogs.com/slgkaifa/p/7191548.html