UVA11426 GCD - Extreme (II) —— 欧拉函数

 

题目链接:https://vjudge.net/problem/UVA-11426

 

 

 

 

题意:

求 ∑ gcd(i,j),其中 1<=i<j<=n 。

 

题解:
1. 欧拉函数的定义:满足 0<x<n 且 gcd(x,n) = 1 的x有euler[n]个。

2. 可以推论出:满足 0<2*x<2*n 且 gcd(2*x,2*n) = 2 的2*x同样有euler[n]个,推向一般:满足 0<k*x<k*n 且 gcd(k*x,k*n) = k 的k*x有euler[n]个。解释:其实就是对于n来说,在1~n-1内与它互质的数都乘上相应的倍数,同时n也乘上相应的倍数,因而他们的最大公约数也为乘上的倍数,但不管如何,个数没有改变,仍为euler[n]个,只不过是他们的值“放大”了罢。

3. 有了上述结论,就可以枚举每个欧拉函数euler[n]和系数k,然后进行统计。

 

AC代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <cmath>
 7 #include <queue>
 8 #include <stack>
 9 #include <map>
10 #include <string>
11 #include <set>
12 using namespace std;
13 typedef long long LL;
14 const int INF = 2e9;
15 const LL LNF = 9e18;
16 const int MOD = 1e9+7;
17 const int MAXN = 4000001+10;
18 
19 int euler[MAXN];
20 void getEuler()
21 {
22     memset(euler, 0, sizeof(euler));
23     euler[1] = 1;
24     for(int i = 2; i<MAXN; i++) if(!euler[i]) {
25         for(int j = i; j<MAXN; j += i)
26         {
27             if(!euler[j]) euler[j] = j;
28             euler[j] = euler[j]/i*(i-1);
29         }
30     }
31 }
32 
33 LL sum[MAXN];
34 void init()
35 {
36     getEuler();
37     memset(sum, 0, sizeof(sum));
38     for(int i = 2; i<MAXN; i++)   // 枚举“单位”欧拉数
39         for(int k = 1; i*k<MAXN; k++)   // 枚举倍数
40             sum[i*k] += k*euler[i];
41 
42     for(int i = 2; i<MAXN; i++)
43         sum[i] += sum[i-1];
44 }
45 
46 int main()
47 {
48     init();
49     int n;
50     while(scanf("%d", &n) &&n)
51         printf("%lld\n", sum[n]);
52 }
View Code

 

posted on 2018-04-03 23:24  h_z_cong  阅读(267)  评论(0编辑  收藏  举报

导航