您的位置:首页 > 其它

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

2016-06-04 13:57 411 查看
题目链接:

SPOJ - VLATTICE Visible Lattice Points

题意:

一个n*n*n的方格,从最左下角(0, 0, 0)最多可以看到多少个点?(不被遮挡)包括方格内部。

分析:

假设能看到的点的坐标为(x,y,z)则必须满足:gcd(x,y,z)=1。(0≤x,y,z≤n)。

当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(1≤x,y≤n)的对数。

当x,y,z均大于0时,相当于求gcd(x,y,z)=1(1≤x,y,z≤n)的对数。

对于后两种情况用莫比乌斯反演解决。别忘了倒数第二种情况需要乘以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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息