数论--欧拉函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数论--欧拉函数相关的知识,希望对你有一定的参考价值。

欧拉函数,用φ(n)表示

欧拉函数是求小于等于n的数中与n互质的数的数目

比如φ(10),小于等于10的数中与10互质的数有1,3,7,9,所以φ(10)=4

 

那么,问题来了,如何求求小于等于n的数中与n互质的数的数目???

比如求φ(10)

先质因子分解,10=2*5,再去掉所有2和5的倍数:2的倍数2,4,6,8,10;5的倍数:5,10;

10-10/2-10/5,但是这样算10去掉了两次,那就加回来,10-10/2-10/5+10/2/5=4(容斥原理)

φ(10)=4;

再比如φ(30)

30=2*3*5;

30-30/2-30/3-30/5+ 30/(2*3) + 30/(2*5) + 30/(3*5) - 30/(2*3*5)=8

φ(30)=8

但是这样算太麻烦了!

看简单方法:

φ(30)   =   30*(1 - 1/2)*(1 - 1/3)*(1 - 1/5)   =   30*(1 - 1/2 - 1/3 - 1/5 + 1/6 + 1/10 + 1/15 - 1/30)

可以发现吧,展开后(划线的)跟上面那个式子(斜体的)其实是一样的

于是,可以写代码:

 1 #include<cstdio>
 2 
 3 int phi(int x){//欧拉函数
 4     int ans = x;
 5     for(int i = 2; i*i <= x; i++){
 6         if(x % i == 0){
 7             ans = ans / i * (i-1);
 8             while(x % i == 0) x /= i;
 9         }
10     }
11     if(x > 1) ans = ans / x * (x-1);
12     return ans;
13 }
14 
15 int main()
16 {
17     printf("%d\\n",phi(30));
18 }

时间复杂度为O(√n)

 

如果要预处理n个数的欧拉函数值,可以用筛子的思想(还记得前面提到的素数筛吗??)

#include<cstdio>
const int N = 100000 + 5;
int phi[N];
void Euler(){
    phi[1] = 1;
    for(int i = 2; i < N; i ++){
        if(!phi[i]){//类似素数筛,phi[i]==0代表i是素数 
            for(int j = i; j < N; j += i){
                if(!phi[j]) phi[j] = j;
                phi[j] = phi[j] / i * (i-1);//i一定是j的素因子 (看for循环环里面的j的变化) 
            }
        }
    }
}
int main(){
    Euler();
    printf("%d\\n",phi[30]);
}

 

性质:

p为质数

1. phi(p)=p-1   因为质数p除了1以外的因数只有p,故1至p的整数只有p与p不互质 

2. 如果i mod p = 0, 那么 phi(i * p)=phi(i) * p       //例:10%2==0,phi(2*10)=phi(10)*2=4*2=8 正解

3.若i mod p ≠0,  那么 phi( i * p )=phi(i) * ( p-1 )   //例:10%3!=0,phi(3*10)=phi(10)*(3-1)=4*2=8 正解

 

公式:

技术分享

超欧拉取模进化公式

 技术分享

 

以上是关于数论--欧拉函数的主要内容,如果未能解决你的问题,请参考以下文章

数论之旅4---欧拉函数的证明及代码实现(我会证明都是骗人的╮( ̄▽ ̄)╭)

数论-欧拉函数

数论一(欧拉函数+费马小定理)

[数论] 欧拉函数

UVA 10820 Send a Table 数论 欧拉函数

欧拉函数总结数论欧拉函数