您的位置:首页 > 其它

「欧拉函数」学习笔记

2018-07-15 16:36 232 查看

欧拉函数$φ(n)$表示整数$1到n$中与$n$互质的数的个数。

 

特殊情况

1. $φ(1) = 1$

2. 当$n$为素数时,$φ(n) = n-1$.

3. 若$n$是素数$p$的$k$次幂,$φ(n) = φ(p^k) = p^k - p^{k-1} = (p-1)p^{k-1}$

(除掉$p$的倍数即可,由于$p^k = p^{k-1} * p$,故共有$p^{k-1}$个$p$的倍数)

性质1. 当$m, n$互质时,$φ(mn) = φ(m)φ(n)$

这就是欧拉函数的积性性质。欧拉函数是积性函数

设有质数$ p_1, p_2 $,则$ φ(p_1^{k_1} * p_2^{k_2}) $按照刚才的方法,总数减去$p_1$的倍数与$p_2$的倍数,再加上重复减掉的$p_1, p_2$的公倍数。

$p_1$的倍数有$ 1 * p_1, 2 * p_1, ... , p_1^{k_1 - 1} * p_2^{k_2} * p_1 $,总共有$p_1^{k_1 - 1} * p_2^{k_2}$个。

同理$p_2$的倍数有$p_1^{k_1} * p_2^{k_2-1}$个。

由于$p_1, p_2互质$,$lcm(p_1, p_2) = p_1 * p_2$,$p_1 * p_2$的倍数有$ 1 * p_1 * p_2, 2 * p_1 * p_2 , ... , p_1^{k_1-1} * p_2^{k_2-1} * p_1 * p_2$,总共有$p_1^{k_1-1} * p_2^{k_2-1}$个

因此我们得到$ φ(p_1^{k_1} * p_2^{k_2}) = p_1^{k_1} * p_2^{k_2} -  (p_1^{k_1 - 1} * p_2^{k_2}) - (p_1^{k_1} * p_2^{k_2-1}) + p_1^{k_1-1} * p_2^{k_2-1}$

然后再按照刚才的思路,分开考虑:

$φ(p_1^{k_1}) = p_1^{k_1} - p_1^{k_1-1}$

$φ(p_2^{k_2}) = p_2^{k_2} - p_2^{k_2-1}$

故$φ(p_1^{k_1}) * φ(p_2^{k_2}) = p_1^{k_1} * p_2^{k_2} -  (p_1^{k_1 - 1} * p_2^{k_2}) - (p_1^{k_1} * p_2^{k_2-1}) + p_1^{k_1-1} * p_2^{k_2-1}$

这两个式子是一模一样的,所以$φ(p_1^{k_1} * p_2^{k_2}) = φ(p_1^{k_1}) * φ(p_2^{k_2})$

所以$φ(mn) = φ(n) * φ(m)$

 

性质2. 欧拉函数的通式 $φ(n) = n * \prod\limits_{i=1}^r \frac{p_i-1}{p_i}$

证明:刚才我们得到了$φ(p^k) = (p-1)p^{k-1}$,又得到了欧拉函数的积性性质$φ(mn) = φ(n) * φ(m)$,也可以以此类推三个,四个……

   因此对于任意一个$φ(n)$,我们可以对$n$进行质因数分解:

      $n = p_1^{k_1}p_2^{k_2}...p_r^{k_r}$

   对于这个$n$,我们依然使用这个方法,得到$φ(n) = φ(p_1^{k_1})φ(p_2^{k_2})...φ(p_r^{k_r})$

   因此就得到了$φ(n) = (p_1^{k_1}-p_1^{k_1-1}) * (p_2^{k_2}-p_2^{k_2-1}) ... (p_r^{k_r}-p_r^{k_r-1})$

    $φ(n) = \prod\limits_{i=1}^r p_i^{k_i-1}(p_i-1)$

         $  = \prod\limits_{i=1}^r p_i^{k_i} * p_i^{-1}(p_i-1)$

          $ = n * \prod\limits_{i=1}^r \frac{p_i-1}{p_i}$

   因此我们得到通式$φ(n) = n * \prod\limits_{i=1}^r \frac{p_i-1}{p_i}$

  有了通式,我们就可以求欧拉函数$φ(n)$了:

int a,b,n,phi
;
main(){
n = r;
if(n == 2){ printf("1"); return 0; }
for(int i = 1; i <= n; ++i) phi[i] = i;
for(int i = 2; i <= n; ++i){
if(phi[i] != i) continue;
for(int j = i; j <= n; j += i) phi[j] = phi[j]/i*(i-1);
}
printf("%lld", phi
);
return 0;
}

    以上代码复杂度是$O(n^2)$的,顺便充当筛素数了。如果$ phi[i]=i $则说明是素数。然后对$n$之内所有以$i$为因子的数都记性上述公式描绘的操作。注意到我们先做了$/i$,然后再做乘。这样是为了避免数据过大而造成数据丢失。

 

性质3. 当$n$为奇数时 $φ(2n)$ = $φ(n)$

   当$n$为奇数时 $φ(2n)$ = $φ(n)$

   怎么证明?我真不知道……还请dalao指教!

   反正这条性质貌似没什么用??

性质4. $φ(p * x) = φ(x) * p\    (p | x)$ (x, p为整数)

证明:由通式可得 $φ(p * x) = p * x * \prod\limits_{i=1}^r \frac{a_i-1}{a_i}$ 

   观察通式我们发现,一个数的欧拉函数其实只和其各个素因数的种类有关,并不关心每种素因数有几个。那么只需要证明$ φ(x) =  x * \prod\limits_{i=1}^r \frac{a_i-1}{a_i}$,也就是 $a_1 ~ a_r$包含了$x$与$x*p$的所有种类的素因数 就好了。

   那么由于$p | x$,说明$p$是$x$的约数,所以$p$的所有约数必然包括在$x$之内,所以$x$的所有种类的素因数都是$p * x$的所有种类的素因数是必然的。

   所以我们可以继续推:

   $ φ(p * x) =  x * p * \prod\limits_{i=1}^r \frac{a_i-1}{a_i}$

   $ φ(p * x) =  φ(x) * p$

性质5. $φ(p * x) = φ(x) * (p-1) $ ($p$与$x$互质,且$p$是质数)

证明:这个证明起来比任何一个都容易。

   首先由于$p$与$x$互质,所以根据性质2, $ φ(p * x) = φ(x) * φ(p) $

   那么由于$p$是质数,所以根据特殊情况2,$ φ(p) = p - 1 $

   故$ φ(p * x) = φ(x) * (p-1) $

 

总结性质5和性质6,当$p$为质数时:若$p|x$,可以利用性质5推得$φ(p * x)$。否则$x \% p ≠ 0$,又因为$p$是质数,所以$x, p$一定互质,所以用性质6就可以推得$φ(p * x)$。因此当$p$为质数时,无论如何都可以推得$φ(p * x)$,因此我们可以利用在线性筛素数的基础上线性完成欧拉函数的求解。

 

/*
* phi[i]用来表示欧拉函数
* isprime[i]用来记录i是否是质数
* p数组用来存质数
*/
int n,tot;
int phi
,isprime
,p
;
int main(){
n = r;
phi[1] = 1;
for(int i = 2; i <= n; ++i){
if(!isprime[i]){
p[++tot] = i;
phi[i] = i-1;    //若i是质数,则根据特殊情况2, φ(i) =  i-1
}
for(int j = 1; j <= tot; ++j){
if(i * p[j] > n) break;  //越界
isprime[i * p[j]] = 1;   //存在因子i和p[j],故一定不是质数
if(i % p[j] == 0){
phi[i * p[j]] = phi[i] * p[j]; /*性质5*/
break;
/*p[j]是i的素因子之一。由于i % p[j] == 0,所以p[j]也是i的素因子之一。
*因为p数组是递增的,因此p[j+1] > p[j],而i内包括了p[j]。p[j]已经作为i * p[j]的素因子了,
*所以p[j+1]就一定不是它的最小素因子了。
*/
}
else phi[i * p[j]] = phi[i] * (p[j] - 1);
/*利用性质6,p[j]是质数*/
}
}
printf("%d",phi
);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: