SPOJ--VLATTICE(莫比乌斯反演)
2016-04-18 22:59:24
题意:一个从(0,0,0)到(N,N,N)的晶格,问从原点能看到多少晶格,即问 gcd(x,y,z)=1的对数(0 <= x , y , z <= N)
思路:典型的mobius,显然需要 gcd(x,y,z)=m,以及 d|gcd(x,y,z) 两种定义,设 F(d) = Sigma(f(m)) ,(d|m); f(m) = number of gcd(x,y,z)=m
所以 f(m) = Sigma(mu(m/d) * F(m)) ,(d|m),预处理mu数组,然后O(n)处理解。
注意考虑 (1,0,0) , (0,1,0) , (0,0,1) 三个点,以及 x=0,y=0,z=0, 时的三个平面上的解。
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <time.h> 5 #include <math.h> 6 #include <vector> 7 #include <map> 8 #include <set> 9 #include <stack> 10 #include <queue> 11 #include <string> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 16 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 17 #define MEM(a,b) memset(a,b,sizeof(a)) 18 #define MP(a,b) make_pair(a,b) 19 #define PB push_back 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const double eps = 1e-8; 24 const int INF = (1 << 30) - 1; 25 const int MAXN = 1000010; 26 27 int T,N; 28 int mu[MAXN]; 29 int vis[MAXN],prime[MAXN],pcnt; 30 31 void Mu_pre(){ 32 memset(vis,0,sizeof(vis)); 33 mu[1] = 1; 34 pcnt = 0; 35 int top = 1000000; 36 for(int i = 2; i <= top; ++i){ 37 if(!vis[i]){ 38 prime[++pcnt] = i; 39 mu[i] = -1; 40 } 41 for(int j = 1; j <= pcnt && i * prime[j] <= top; ++j){ 42 vis[i * prime[j]] = 1; 43 if(i % prime[j]) mu[i * prime[j]] = -mu[i]; 44 else{ 45 mu[i * prime[j]] = 0; 46 break; 47 } 48 } 49 } 50 } 51 52 int main(){ 53 Mu_pre(); 54 scanf("%d",&T); 55 while(T--){ 56 scanf("%d",&N); 57 ll ans = 3; 58 for(int i = 1; i <= N; ++i) ans += 1ll * mu[i] * (N / i) * (N / i) * (N/ i + 3); 59 printf("%lld\n",ans); 60 } 61 return 0; 62 }

浙公网安备 33010602011771号