SPOJ VLATTICE(莫比乌斯反演)
题意:
在一个三维空间中,已知(0,0,0)和(n,n,n),求从原点可以看见多少个点
思路:
如果要能看见,即两点之间没有点,所以gcd(a,b,c) = 1 /*来自kuangbin
利用推GCD(a,b)的方法,可以推出GCD(a,b,c) = 1的个数等于mu[i]*(n/i)*(n/i)*(n/i)的和
然而是从0点开始的,而我们只能从1开始计算,因为少了0周围的所有ans初始+3
对于A(0,0,1),所以在计算mu[i]*(n/i)*(n/i)*(n/i)时,我们忽略了A与x,y轴的求出来点的关联情况,所以加上
(n/i)*(n/i),而且有3个点所以每次要加上3*(n/i)*(n/i). /*纯属个人理解- -
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <vector> #include <algorithm> #include <functional> typedef long long ll; using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 1000000+10; int is_prime[maxn]; int prime[maxn]; int sum[maxn]; int mu[maxn]; int tot; int a,b,c,d,k; ll Min(ll x,ll y) { if(x < y) return x; else return y; } void Moblus() { tot = 0; memset(is_prime,0,sizeof(is_prime)); mu[1] = 1; for(int i = 2; i <= maxn; i++) { if(!is_prime[i]) { prime[tot++] = i; mu[i] = -1; } for(int j = 0; j < tot; j++) { if(prime[j]*i>maxn) break; is_prime[i*prime[j]] = 1; if(i % prime[j]) //prime[j]不重复 { mu[i*prime[j]] = -mu[i]; } else { mu[i*prime[j]] = 0; break; } } } } int main() { int T,n; Moblus(); scanf("%d",&T); while(T--) { scanf("%d",&n); ll ans = 3; for(int i = 1;i <= n;i++) ans += (ll)mu[i]*((ll)(n/i)*(n/i)*(n/i) + (ll)(n/i)*(n/i)*3); printf("%lld\n",ans); } return 0; }