1.pk的欧拉函数
对于给定的一个素数 p , φ(p) = p -1。则对于正整数 n = pk ,
φ(n)= pk - pk -1
证明:小于 pk的正整数个数为 pk- 1个,其中 和 pk不互质的正整数有{p * 1,p* 2,...,p * (pk - 1-1)}共计pk - 1 - 1 个
所以 φ(n) = pk- 1 - (pk - 1- 1) = pk- pk- 1
2. p * q的欧拉函数
假设 p, q是两个互质的正整数,则 p * q 的欧拉函数为
φ(p * q) = φ(p) * φ(q) , gcd(p, q) =1 。
证明: 令 n = p * q,gcd(p,q) = 1,根据剩余定理,有Zn和 Zp ×Zq 之间存在一一映射( a ∈ Zp ,b ∈ Zq ⇔ b * p + a * q ∈ Zn )
所以 n的完全余数集合的元素个数等于集合 Zp × Zq的元素个数, 而后者的元素个数为 φ(p) * φ(q)
所以有φ(p * q) = φ(p)* φ(q)
3.任意正整数的欧拉函数
任意一个整数 n 都可以表示为其素因子的乘积(算术基本定理)为:
m
n= ∏ piki (m 为 n 的素因子的个数)
i=1
根据前面两个结论,很容易得出它的欧拉函数为:
m m
Φ(n) = ∏ piki-1(pi-1) = n * ∏ (1 - 1/pi) 对于任意 n > 2,2 | Φ(n) ,因为必存在 pi -1 是偶数。
i=1 i=1
下面讨论对于任意整数我们怎么用程序实现欧拉函数公式:
因为要分解质因数,我们先用素数筛得到一张素数表:
int const MAX = 1e6 + 2;
int prime[MAX];
void get_prime()
{
memset(prime,1,sizeof(prime));
prime[1] = 0;
for(int i = 2; i * i <= MAX; i++)
if(prime[i])
for(int j = i * i; j <= MAX; j += i)
prime[j] = 0;
}
然后就可利用素数表"分解质因数",再用上述公式通过筛选得到欧拉函数表:
void euler()
{
for(int i = 1; i <= MAX; i++)
euler[i] = i; //初始化值为本身
for(int i = 2; i <= MAX; i++)
if(prime[i]) //"分解质因数"
for(int j = i; j <= MAX; j += i)
//这步操作类似素数筛,用来筛选与j互素的数的个数
//先进行除法是为了防止中间数据溢出
euler[j] = euler[j] / i * (i - 1);
}
这里举euler[18]的例子解释下euler[j] = euler[j] / i * (i - 1)这步操作的用途
一开始euler[18] = 18,质数从2开始枚举,因为2是18的因子
所以第一次我们可以得到euler[18] = euler[18] / 2 * (2 - 1) = 9
此时euler[18] = 9,9表示小于18的数当中不是2的倍数的数的个数,即1,3,5,7,9,11,13,15,17。
质数到3,因为3也是18的因子,所以euler[18] = euler[18] / 3 * (3 - 1) = 6
此时euler[18] = 6,6表示小于18的数当中不是2且不是3的倍数的数的个数之和,表示的数为1,5,7,11,13,17。
质数到5,因为5不是18的因子,故不会影响euler[18]的值
以此类推最后我们得到euler[18] = 6 (即18与1,5,7,11,13,17这些数互素)