欧拉函数入门

定义

在数论,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目

公式

φ(x)=x ∏ i = 1 N ( 1 − 1 p i ) \prod_{i=1}^N{(1-\frac{1}{p_i})} i=1N(1pi1) (其中p1, p2……pn为x的所有质因数)

证明

我觉得网上许多博客的证明不太严谨,我严格证明一下

首先明白两个性质
1:当n= p k p^k pk (且p是质数的情况下) φ(n)= p k p^k pk- p k − 1 p^{k-1} pk1
因为显然n的质因子只有一个就是p,那么1-n中不和他互素的就是因子含有p的数即 p×1,p×2,p×3… p× p k − 1 p^{k-1} pk1即总共有 p k − 1 p^{k-1} pk1个数,而总数有 p k p^{k} pk,那么结果就是 p k p^{k} pk- p k − 1 p^{k-1} pk1

2:欧拉函数是积性函数,但不是完全积性函数。若m,n互质,则φ(m∗n)=φ(m)∗φ(n),这个我不会证明,直接看维基百科的证明吧:证明:设A, B, C是跟m, n, mn互质的数的集,据中国剩余定理,A×B×C可建立双射(一一对应)的关系

而x= p 1 k 1 {p_1}^{k_1} p1k1 × p 2 k 2 {p_2}^{k_2} p2k2 × p 3 k 3 {p_3}^{k_3} p3k3 p n k n {p_n}^{k_n} pnkn

φ(x)=( p 1 k 1 {p_1}^{k_1} p1k1- p 1 k 1 − 1 {p_1}^{{k_1}-1} p1k11)( p 2 k 2 {p_2}^{k_2} p2k2- p 2 k 2 − 1 {p_2}^{{k_2}-1} p2k21)…( p n k n {p_n}^{k_n} pnkn- p n k n − 1 {p_n}^{{k_n}-1} pnkn1)=x ∏ i = 1 N ( 1 − 1 p i ) \prod_{i=1}^N{(1-\frac{1}{p_i})} i=1N(1pi1)

性质

1:对于质数p,φ ( p )=p−1。显然

2:…

还有一些其他性质,暂时不要用到,先不再学习

模板题

复杂度是n× n 2 \sqrt[2]{n} 2n

#include
#include
#include
#include
#include
#include
#include
#define fi first
#define se second
#define debug printf("I am here\n");
using namespace std;
typedef long long ll;
const int maxn=3e5+5,inf=0x3f3f3f3f,mod=998244353,lim=1e7+5e6;
const ll INF=0x3f3f3f3f3f3f3f3f;
int t,n;
int euler(int x){
    int ans=x;
    for(ll i=2;i*i<=x;i++){
        if(x%i==0){
            ans=ans/i*(i-1);
            while(x%i==0){
                x=x/i;
            }
        }
    }
    if(x!=1){
        ans=ans/x*(x-1);
    }
    return ans;
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        printf("%d\n",euler(n));
    }
    return 0;
}

但是如果n比较大,要求[1,n]的所有欧拉函数,是不是很像求质数,先用埃式筛

void euler(int n){
    for (int i=1;i<=n;i++){
        phi[i]=i;
    } 
    for (int i=2;i<=n;i++){
        if (phi[i]==i){//这代表i是质数
            for (int j=i;j<=n;j+=i){
                phi[j]=phi[j]/i*(i-1);//把i的倍数更新掉
            }
        }
    }
}

既然有埃式,那么就有线性筛,线性筛有点难懂

前提是要懂欧拉筛。每个数被最小的因子筛掉的同时,再进行判断。i表示当前做到的这个数,prime[j]表示当前做到的质数,那要被筛掉的合数就是i*prime[j]。若prime[j]在这个合数里只出现一次(i%prime[j]!=0),也就是i和prime[j]互质时,则根据欧拉函数的积性函数的性质,phi[i * prime[j]]=phi[i] * phi[prime[j]]。若prime[j]在这个合数里出现了不止一次(i%prime[j]=0),也就是这个合数的所有质因子都在i里出现过,那么根据公式,φ(i * prime[j])=prime[j] * i * ∏ i = 1 N ( 1 − 1 p i ) \prod_{i=1}^N{(1-\frac{1}{p_i})} i=1N(1pi1) 。复杂度为O(n)。
还是看代码吧:

void euler(int n){
	phi[1]=1;//1要特判 
	for (int i=2;i<=n;i++){
		if (flag[i]==0){//这代表i是质数 
			prime[++num]=i;
			phi[i]=i-1;
		}
		for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法 
		{
			flag[i*prime[j]]=1;//先把这个合数标记掉 
			if (i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子 
				break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次 
			}else{
                phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质 
			} 
		}
	}
}

参考链接:https://blog.csdn.net/liuzibujian/article/details/81086324

你可能感兴趣的:(数论)