poj2478 ——欧拉函数入门题

题目链接:http://poj.org/problem?id=2478

题目大意:

  给你一个数列f(N),这个数列是由一系列不能约分的分数 a / b (0 < a < b <= n 且 (a,b) = 1)按照递增的顺序排列而成的。输入一个N,求这个数列中元素的个数。

题目思路:

  因为题目只需要求出元素的个数,所以,把分母相同的放在一起,然后就发现规律了,其实就是求从2到 n 的欧拉函数的和。范围只有10^6,可以打表预处理。思路很清晰。因为要反复用欧拉函数,所以比较快的方法是用递推的方法求。

  

1   for (i = 1; i <= maxn; ++i) f[i] = i;
2   for (i = 2; i <= maxn; i+=2) f[i] /= 2;
3   for (i = 3; i <= maxn; i+=2){
4     if (f[i] == i){
5       for (j = i; j <= maxn; j+=i){
6         f[j] = f[j] / i * (i - 1);
7       }
8     }
9   }

  

  这个方法和筛法求素数比较类似,貌似就是那个思想。模拟一下什么就懂了。这里也用到了欧拉函数的性质:φ(n) = n * (1 - 1/p1) * (1 - 1/p2) * …… * (1 - 1/pk)。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cctype>
 6 #include <stack>
 7 #include <queue>
 8 #include <map>
 9 #include <set>
10 #include <vector>
11 #include <cmath>
12 #include <algorithm>
13 #define lson l, m, rt<<1
14 #define rson m+1, r, rt<<1|1
15 using namespace std;
16 typedef long long int LL;
17 const int MAXN =  0x3f3f3f3f;
18 const int  MIN =  -0x3f3f3f3f;
19 const double eps = 1e-9;
20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1},
21   {1,1},{1,-1},{-1,-1}};
22 
23 const int maxn = 1000000+10;
24 int f[maxn];
25 int main(void){
26 #ifndef ONLINE_JUDGE
27   freopen("poj2478.in", "r", stdin);
28 #endif
29 
30   LL i, j;
31   for (i = 1; i <= maxn; ++i) f[i] = i;
32   for (i = 2; i <= maxn; i+=2) f[i] /= 2;
33   for (i = 3; i <= maxn; i+=2){
34     if (f[i] == i){
35       for (j = i; j <= maxn; j+=i){
36         f[j] = f[j] / i * (i - 1);
37       }
38     }
39   }
40   //printf("%d\n", f[5]);
41   //for (i = 2; i <= 14; ++i) printf("f[%d] = %d\n", i, f[i]);
42   //for (i = 2; i <= 14; ++i) printf("f[] = %d\n", f[i]);
43   int n;
44   while (~scanf("%d", &n)){
45     if (!n) break; LL ans = 0;
46     for (i = 2; i <= n; ++i){
47       ans += f[i]; //printf("f[%d] = %d ", i, f[i]);
48     }
49     printf("%lld\n", ans);
50   }
51 
52   return 0;
53 }

  写代码的时候还是遇到了一些问题,比如把改写成 j 的地方写成了 i ,还好很快找到了,以后这种错误从一开始就不要犯。

  调试的时候发现一个很神奇的现象,不能解释啊。41行的注释,输出来 f[i] 的值都是0!42行的注释输出来就是正常的!好吧,原因到现在我还不知道……貌似是语言的细节?希望神牛路过指点啊~

  另外,求的时候,没有必要每次都加一遍,也可以把f[]数组进一步处理,让f[n]保存前n项得欧拉函数的和,这样就可以直接输出f[n]的值了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cctype>
 6 #include <stack>
 7 #include <queue>
 8 #include <map>
 9 #include <set>
10 #include <vector>
11 #include <cmath>
12 #include <algorithm>
13 #define lson l, m, rt<<1
14 #define rson m+1, r, rt<<1|1
15 using namespace std;
16 typedef long long int LL;
17 const int MAXN =  0x3f3f3f3f;
18 const int  MIN =  -0x3f3f3f3f;
19 const double eps = 1e-9;
20 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1},
21   {1,1},{1,-1},{-1,-1}};
22 
23 const int maxn = 1000000+10;
24 LL f[maxn];
25 int main(void){
26 #ifndef ONLINE_JUDGE
27   freopen("poj2478.in", "r", stdin);
28 #endif
29 
30   LL i, j;
31   for (i = 1; i <= maxn; ++i) f[i] = i;
32   for (i = 2; i <= maxn; i+=2) f[i] /= 2;
33   for (i = 3; i <= maxn; i+=2){
34     if (f[i] == i){
35       for (j = i; j <= maxn; j+=i){
36         f[j] = f[j] / i * (i - 1);
37       }
38     }
39   }
40   for (i = 3; i <= maxn; ++i){
41     f[i] += f[i-1];
42   }
43   //printf("%d\n", f[5]);
44   //for (i = 2; i <= 14; ++i) printf("f[%d] = %d\n", i, f[i]);
45   //for (i = 2; i <= 14; ++i) printf("f[] = %d\n", f[i]);
46   int n;
47   while (~scanf("%d", &n)){
48     if (!n) break; LL ans = 0;
49     /*
50     for (i = 2; i <= n; ++i){
51       ans += f[i]; //printf("f[%d] = %d ", i, f[i]);
52     }
53     */
54     printf("%lld\n", f[n]);
55   }
56 
57   return 0;
58 }

  速度快了一点儿~这种预处理的方法学习一下。

posted on 2013-04-22 12:58  aries__liu  阅读(228)  评论(0编辑  收藏  举报