BZOJ2818 Gcd

首先线性筛出phi()

然后枚举每个素数p,考虑p对答案的贡献:

gcd(i, j) = p <=> gcd(i / p, j / p) = 1

令x = i / p, y = j / p,再不妨x >= y,则

(1)x = y,只有x = y = 1

(2)x > y,x的个数就有phi(y)个

所以p对答案的贡献就是(2 * Σ phi(y)) - 1

故我们对phi()前缀和一下,再枚举质数p,直接计算就可以了

 1 /**************************************************************
 2     Problem: 2818
 3     User: rausen
 4     Language: C++
 5     Result: Accepted
 6     Time:1076 ms
 7     Memory:131664 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <cstring>
12   
13 using namespace std;
14 const int N = 10000005;
15 int n, tot;
16 int phi[N], p[N / 10];
17 long long ans, sum[N];
18 bool Flag[N];
19   
20 void get_phi(int N){
21     memset(Flag, 0 , sizeof(Flag));
22     phi[1] = 1;
23     int i, j, k;
24     for (i = 2; i <= N; ++i){
25         if (!Flag[i])
26             p[++tot] = i, phi[i] = i - 1;
27         for (j = 1; j <= tot; ++j){
28             if ((k = i * p[j]) > N) break;
29             Flag[k] = 1;
30             if (    i % p[j] == 0){
31                 phi[k] = phi[i] * p[j];
32                 break;
33             }
34             phi[k] = phi[i] * (p[j] - 1);
35         }
36     }
37 }
38   
39 int main(){ 
40     scanf("%d", &n);
41     get_phi(n);
42     int i;
43     for (i = 1; i <= n; ++i)
44         sum[i] = sum[i - 1] + phi[i];
45     for (i = 1; i <= tot; ++i)
46         ans += sum[n / p[i]] * 2 - 1;
47     printf("%lld
", ans);
48     return 0;
49 }
View Code
By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
原文地址:https://www.cnblogs.com/rausen/p/4345414.html