SPOJ - VLATTICE Visible Lattice Points(gcd(x,y,z)=1的对数/莫比乌斯反演)

来源:互联网 发布:mysql如何导入数据 编辑:程序博客网 时间:2024/04/30 22:24

题目链接:
SPOJ - VLATTICE Visible Lattice Points
题意:
一个n*n*n的方格,从最左下角(0, 0, 0)最多可以看到多少个点?(不被遮挡)包括方格内部。
分析:
假设能看到的点的坐标为(x,y,z)则必须满足:gcd(x,y,z)=1(0x,y,zn)
x=y=z=0时是不成立的。
x,y,z中有两个为0时,只有三种情况(0,0,1),(0,1,0),(1,0,0).
x,y,z中有一个为0时,相当于求gcd(x,y)=1(1x,yn)的对数。
x,y,z均大于0时,相当于求gcd(x,y,z)=1(1x,y,zn)的对数。
对于后两种情况用莫比乌斯反演解决。别忘了倒数第二种情况需要乘以3,因为1的位置有三种。

#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <algorithm>#include <bitset>using namespace std;typedef long long ll;const int MAX_N = 1000010;int prime_cnt;int prime[MAX_N], mu[MAX_N], sum[MAX_N];bitset<MAX_N> bs;void GetMu(){    bs.set();    prime_cnt = 0;    mu[1] = 1;    for(int i = 2; i < MAX_N; ++i ) {        if(bs[i] == 1) {            prime[prime_cnt++] = i;            mu[i] = -1;        }           for(int j = 0; j < prime_cnt && i * prime[j] < MAX_N; ++j ){            bs[i * prime[j]] = 0;            if(i % prime[j]) {                mu[i * prime[j]] = -mu[i];            }else {                mu[i * prime[j]] = 0;                break;            }        }    }    for(int i = 1; i < MAX_N; i++) {        sum[i] = sum[i - 1] + mu[i];    }}ll solve(int n){    int last;    ll ans = 3; //当有两个数是0时,有3种情况    for(int i = 1; i <= n; ++i) {        last = n / (n / i);        ll tmp =(ll)(n / i);        //当x, y, z均大于0时        ans += tmp * tmp * tmp * (sum[last] - sum[i - 1]);        //当有1个数为0时,相当于gcd(x, y) = 1的对数,但是考虑0的位置有3种,所以要乘上3        ans += tmp * tmp * (sum[last] - sum[i - 1]) * 3;        i = last;    }    return ans;}int main(){    GetMu();    int T, n;    scanf("%d", &T);    while(T--){        scanf("%d", &n);        printf("%lld\n", solve(n));    }    return 0;}
0 0
原创粉丝点击