欧拉函数

定义:

1 ∼ N 1 \sim N 1N 中与 N N N 互质的数的个数被称为欧拉函数,记为 φ ( N ) \varphi(N) φ(N)
已知 N = P 1 a 1 P 2 a 2 P 3 a 3 . . . P n a n N=P_1^{a_1}P_2^{a_2}P_3^{a_3}...P_n^{a_n} N=P1a1P2a2P3a3...Pnan
φ ( x ) = x ∏ i = 1 n ( 1 − 1 P i ) \varphi(x)=x\prod_{i=1}^{n} (1-\frac{1}{P_i}) φ(x)=xi=1n(1Pi1)
定义 φ ( 1 ) = 1 \varphi(1)=1 φ(1)=1

证明:

思路:容斥原理
首先考虑去掉 P 1 , P 2 . . . P n P_1,P_2...P_n P1,P2...Pn的所有倍数,即
N − N P 1 − N P 2 − . . . − N P n N-\frac{N}{P_1}-\frac{N}{P_2}-...-\frac{N}{P_n} NP1NP2N...PnN
但是这样可能会同时去掉 P i P_i Pi P j P_j Pj的倍数,这样就被去掉了两次,所以要加上所有 P i ∗ P j P_i*P_j PiPj的倍数
但是会出现 P i P_i Pi, P j P_j Pj, P k P_k Pk的倍数,这样它会被 P i P_i Pi, P j P_j Pj, P k P_k Pk分别减去一次,被 P i P_i Pi, P j P_j Pj加上一次,被 P j P_j Pj, P k P_k Pk加上一次,被 P i P_i Pi, P k P_k Pk加上一次,这样会抵消,但是必须减去它,故而要减去它一次。
以此类推,最后有:
N ( 1 − 1 P 1 − 1 P 2 − . . . − 1 P n N(1-\frac{1}{P_1}-\frac{1}{P_2}-...-\frac{1}{P_n} N(1P11P21...Pn1
+ 1 P 1 P 2 + 1 P 2 P 3 + 1 P 1 P 3 + . . . + 1 P n − 1 P n +\frac{1}{P_1P_2}+\frac{1}{P_2P_3}+\frac{1}{P_1P_3}+...+\frac{1}{P_{n-1}P_n} +P1P21+P2P31+P1P31+...+Pn1Pn1
− 1 P 1 P 2 P 3 − 1 P 2 P 3 P 4 − . . . − 1 P n − 2 P n − 1 P n -\frac{1}{P_1P_2P_3}-\frac{1}{P_2P_3P_4}-...-\frac{1}{P_{n-2}P_{n-1}P_n} P1P2P31P2P3P41...Pn2Pn1Pn1
. . . ) ...) ...)
就等价于 N ∏ i = 1 n ( 1 − 1 P i ) N\prod_{i=1}^{n} (1-\frac{1}{P_i}) Ni=1n(1Pi1)

性质:

1. 1. 1.欧拉函数是积性函数,若 m , n m,n m,n互质,则 φ ( m n ) = φ ( n ) φ ( m ) \varphi(mn)=\varphi(n)\varphi(m) φ(mn)=φ(n)φ(m)
2. 2. 2. n n n为质数时, φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n1
3. 3. 3. n n n为奇质数时, φ ( 2 n ) = φ ( n ) \varphi(2n)=\varphi(n) φ(2n)=φ(n)

#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
     
    cin>>t;
    while(t--){
     
        cin>>n;
        int res=n;
        for(int i=2;i<=n/i;i++){
     
            if(n%i==0){
     
                while(n%i==0) n/=i;
                res=res/i*(i-1);
            }
        }
        if(n>1) res=res/n*(n-1);
        cout<<res<<endl;
    }
}

筛法求欧拉函数:

筛的时候如果筛到质数直接赋值,因为当 n n n为质数时, φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n1,因为 1 ∼ n − 1 1\sim n-1 1n1中每一个数都与 n n n互质。

另一种情况筛到的数 i i i不为质数时

i % p r i m e s [ j ] = 0 i\%primes[j]=0 i%primes[j]=0
φ ( i ∗ p r i m e s [ j ] ) = φ ( i ) ∗ p r i m e s [ j ] \varphi(i*primes[j])=\varphi(i)*primes[j] φ(iprimes[j])=φ(i)primes[j]
i % p r i m e s [ j ] ≠ 0 i\%primes[j]\ne0 i%primes[j]=0
φ ( i ∗ p r i m e s [ j ] ) = φ ( i ) ∗ φ ( p r i m e s [ j ] ) = φ ( i ) ∗ ( p r i m e s [ j ] − 1 ) \varphi(i*primes[j])=\varphi(i)*\varphi(primes[j])=\varphi(i)*(primes[j]-1) φ(iprimes[j])=φ(i)φ(primes[j])=φ(i)(primes[j]1)

给定一个正整数 n n n,求 1 ∼ n 1\sim n 1n中每个数的欧拉函数之和。

时间复杂度 O ( n ) O(n) O(n)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,primes[N],euler[N],cnt;
bool st[N];
void get_eulers(int n){
     
    euler[1]=1;
    for(int i=2;i<=n;i++){
     
        if(!st[i]){
     
            primes[cnt++]=i;
            euler[i]=i-1;
        }
        for(int j=0;primes[j]<=n/i;j++){
     
            int t=primes[j]*i;
            st[t]=1;
            if(i%primes[j]==0){
     
                euler[t]=primes[j]*euler[i];
                break;
            }
            euler[t]=(primes[j]-1)*euler[i];
        }
    }
}
int main(){
     
    cin>>n;
    get_eulers(n);
    long long int res=0;
    for(int i=1;i<=n;i++) res+=euler[i];
    cout<<res<<endl;
}

你可能感兴趣的:(算法)