题目大意:
从坐标(0,0,0)处观察到所有在(n,n,n)范围内的点的个数,如果一条直线上出现多个点,除了第一个,后面的都视为被遮挡了
这题目稍微推导一下可得知 gcd(x,y,z) = 1的点是可观察到的,若三者的gcd>1,则这个点之前必然出现了一个(x/gcd(x,y,z) , y/gcd(x,y,z) , z/gcd(x,y,z))的点
那么因为 0 是无法计算gcd的 , 所以先不考虑0
1. x>0 , y>0 , z>0 ans = ∑x<=n∑y<=n∑z<=n[gcd(x,y,z)=1] -> ∑x<=n∑y<=n∑z<=n∑d|gcd(x,y,z) mu[d]
2. 只存在一个0 ans = 3*(∑x<=n∑y<=n[gcd(x,y)=1]) -> 3*(∑x<=n∑y<=n∑d|gcd(x,y) mu[d])
3.3个数两个为0 ans = 3
那么只要将上面的3个值相加就是我们要求的答案了
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 const int MAXN = 1000000; 5 #define ll long long 6 int mu[MAXN+5] , prime[MAXN/10]; 7 bool check[MAXN+5]; 8 9 void getMu(int n) 10 { 11 memset(check , 0 , sizeof(check)); 12 int tot=0; 13 check[1] = true , mu[1]=1 , mu[2]=-1; 14 for(int i=2 ; i<=n ; i++){ 15 if(!check[i]) prime[tot++]=i , mu[i]=-1; 16 check[i] = true; 17 for(int j=0 ; j<tot ; j++){ 18 if(i*prime[j]>n) break; 19 check[i*prime[j]]=true; 20 if(i%prime[j] == 0){ 21 mu[i*prime[j]] = 0; 22 break; 23 }else{ 24 mu[i*prime[j]] = -mu[i]; 25 } 26 } 27 } 28 } 29 30 int main() 31 { 32 // freopen("a.in" , "r" , stdin); 33 getMu(MAXN); 34 int T , n; 35 scanf("%d" , &T); 36 while(T--) 37 { 38 scanf("%d" , &n); 39 ll ans = 0; 40 for(int i=1 ; i<=n ; i++){ 41 ll tmp1 = (ll)(n/i)*(n/i)*(n/i)*mu[i]; //坐标中一个零都不存在的情况 42 ll tmp2 = (ll)3*(n/i)*(n/i)*mu[i]; //坐标中有一个零的情况 43 ll tmp3 = (ll)3*(n/i)*mu[i]; //坐标中有两个零的情况 44 ans += tmp1+tmp2+tmp3; 45 } 46 printf("%lld\n" , ans); 47 } 48 return 0; 49 }
时间: 2024-10-30 14:16:21