Visible Lattice Points (莫比乌斯反演)

Visible Lattice Points

题意 : 从(0,0,0)出发在(N,N,N)范围内有多少条不从重合的直线;我们只要求gcd(x,y,z) = 1; 的点有多少个就可以了;

比如 : 点(2,4,6)可以等价成(1,2,3)即经过(1,2,3)的线一定经过(2,4,6);

莫比乌斯反演的模板题, 由于点坐标可以为0 , 需要考虑 x, y, z 中两个为0 和一个为0 的情况 :

两个为0 时 : 有 三个点(在x , y, z 轴上); 一个为0 时 : mu[i] * (n/i) * (n/i) * 3;

即 : mu[i] * (n/i) * (n/i)* (n/i+3) + 3;

#include<iostream>
#include<cstring>

using namespace std;
#define ll long long
const int maxn = 1000005;

ll mu[maxn], pri[maxn], T, cnt, vis[maxn];

void init()     
{
    memset(vis, 0 , sizeof(vis));
    memset(mu,0,sizeof(mu));
    mu[1] = 1;
    cnt = 0;
    ll n = 1000005;
    for(ll i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            mu[i] = -1;
            pri[cnt++] = i;
        }
        for(ll j = 0; j < cnt&&i*pri[j] <= n; j++)
        {
            ll k = i*pri[j];
            vis[k] = 1;
            if(i%pri[j] == 0) {mu[k] = 0; break;}
            else mu[k] = -mu[i];
        }
    }
}

int main()
{
    // ios::sync_with_stdio(false);

    init();
    cin >> T;
    while(T--)
    {
        ll n;
        cin >> n;
        ll ans = 3;
        for(ll i = 1; i <= n; i++)
            ans += (ll)(mu[i] * (n/i) * (n/i)* (n/i+3));
        cout << ans  << endl;

    }
    return 0;


}

猜你喜欢

转载自www.cnblogs.com/mrh-acmer/p/9451709.html