欧拉函数
欧拉函数
欧拉函数是数论中很重要的一个函数,欧拉函数是指:对于一个正整数n,小于n且和n互质的正整数的个数,记做:φ(n),其中φ(1)被定义为1,但是并没有任何实质的意义。
定义小于n且和n互质的数构成的集合为Zn,称呼这个集合为n的完全余数集合。
显然,对于素数p,φ(p)= p -1.对于两个素数p、q,他们的乘积n = pq 满足φ(n) =(p-1)(q-1)
证明:对于质数p,q,满足φ(n) =(p-1)(q-1)
考虑n的完全余数集Zn = { 1,2,....,pq -1}
而不和n互质的集合由下面三个集合的并构成:
1) 能够被p整除的集合{p,2p,3p,....,(q-1)p} 共计q-1个
2) 能够被q整除的集合{q,2q,3q,....,(p-1)q} 共计p-1个
3) {0}
很显然,1、2集合中没有共同的元素,因此Zn中元素个数 = pq - (p-1 + q- 1 + 1) = (p-1)(q-1)
上式中黑体的1是它本身,因为是小于它且和它互质的数,所以当然必须减去自身了。
欧拉函数的定义:E(k)=([1,n-1]中与n互质的整数个数).因为任意正整数都可以唯一表示成如下形式:
k=p1^a1*p2^a2*……*pi^ai;(即分解质因数形式)
可以推出:E(k)=(p1-1)(p2-1)……(pi-1)*(p1^(a1-1))(p2^(a2-1))……(pi^(ai-1))
=k*(p1-1)(p2-1)……(pi-1)/(p1*p2*……pi);
=k*(1-1/p1)*(1-1/p2)....(1-1/pk)
= k*(p1-1)/p1 * (p2 - 1) / p2 .......
/*在程序中利用欧拉函数如下性质,可以快速求出欧拉函数的值(a为N的质因素)
若(N%a==0 && (N/a)%a==0) 则有:E(N)=E(N/a)*a;
若(N%a==0 && (N/a)%a!=0) 则有:E(N)=E(N/a)*(a-1);
*/
一般解法:
2
3 void genPhi(int n) /* 求数组phi(i)的例程, n为最大的i+1 */
4 {
5 int i, j, pNum = 0 ;
6 memset(phi, 0, sizeof(phi)) ;
7 phi[1] = 1 ;
8 for(i = 2; i < n; i++)
9 {
10 if(!phi[i])
11 {
12 for(j = i; j < n; j += i)
13 {
14 if(!phi[j])
15 phi[j] = j;
16 phi[j] = phi[j] / i * (i - 1);
17 }
18 }
19 }
20 }
快速求法:
2 {
3 ll num = 0 ,i,j;
4
5 phi[1] = 1 ;
6
7 CL(f,false) ;
8
9 for(i = 2 ; i <= 100000;i++)
10 {
11
12 if(f[i] == false)
13 {
14 prim[num++] = i;
15 phi[i] = i - 1 ;
16 }
17 for(j = 0;j< num&&prim[j]*i <= 100000;j++)
18 {
19 f[i*prim[j]] = true ;
20 if(i%prim[j] == 0)
21 {
22 phi[i*prim[j]] = phi[i] *prim[j] ;
23
24 }
25 else
26 phi[i*prim[j]] = phi[i]*(prim[j] - 1) ;
27
28 }
29 }
}
http://poj.org/problem?id=2478
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<string>
11 #define inf 0x7fffffff
12 #define maxn 1600000
13 #define CL(a,b) memset(a,b,sizeof(a))
14 #define ll long long
15 #define mx 1000010
16 using namespace std;
17
18
19 bool f[maxn] ;
20 ll phi[maxn] ;//记录欧拉函数值
21 ll prim[maxn] ;
22 ll ans[maxn] ;
23
24 void init()// 素数筛选 及求 欧拉函数值
25 {
26 ll num = 0 ,i,j;
27
28 phi[1] = 1 ;
29
30 CL(f,false) ;
31
32 for(i = 2 ; i < mx;i++)
33 {
34
35 if(f[i] == false)
36 {
37 prim[num++] = i;
38 phi[i] = i - 1;
39 }
40 for(j = 0;j< num&&prim[j]*i < mx;j++)
41 {
42 f[i*prim[j]] = true ;
43 if(i%prim[j] == 0)
44 {
45 phi[i*prim[j]] = phi[i] *prim[j] ;
46
47 }
48 else
49 phi[i*prim[j]] = phi[i]*(prim[j] - 1) ;
50
51 }
52 }
53
54 ans[1] = ans[0] = 0 ;
55 for(i = 2; i < mx;i++)
56 ans[i] = ans[i-1] + phi[i] ;
57
58
59
60
61 }
62 int main()
63 {
64 int n ;
65 init() ;
66
67 while(scanf("%d",&n),n)
68 {
69
70
71 printf("%I64d\n",ans[n]) ;
72 }
73 }