【数学知识】三种方法求 [1,n] 中所有数欧拉函数(线性筛欧拉函数优化至 O(n) )

整理的算法模板合集: ACM模板


①直接求小于或等于n,且与n互质的数个数(求[1,n]中所有数的欧拉函数时间复杂度: O ( n n ) O(n\sqrt{n}) O(nn )

②求[1,n]之间每个数的质因数的个数(求[1,n]中所有数的欧拉函数时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

③线性筛欧拉函数求[1,n]之间每个数的质因数的个数(求[1,n]中所有数的欧拉函数时间复杂度: O ( n ) O(n) O(n)

第三种方法的证明

三种方法求欧拉函数

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>

using namespace std;
typedef long long ll;
const int N = 500007, M = 50007, INF = 0x3f3f3f3f;
const double eps = 1e-6;

int n, m;

//欧拉函数,在分解质因数的同时求得欧拉函数
//①直接求小于或等于n,且与n互质的数个数:
inline int euler_one(int n)
{
    int ans = n;
    for(int i = 2;  i * i <= n; ++ i){
        if(n % i == 0){
            ans = ans / i * (i - 1);
            while(n % i == 0)n /= i;
        }
    }
    if(n > 1)ans = ans / n * (n - 1);
    return ans;
}

//②筛选模板:求[1,n]之间每个数的质因数的个数
int euler[N];
inline int euler_all(int n)
{
    memset(euler, 0, sizeof euler);
    euler[1] = 1;
    for(int i = 2; i <= n; ++ i){
        if(!euler[i]){
            for(int j = i; j <= n; j += i){
                if(!euler[j])
                    euler[j] = j;//等同于求一个欧拉函数时的int ans = n;
                euler[j] = euler[j] / i * (i - 1);
            }
        }
    }
}


//线性筛欧拉函数建立在线性筛素数的基础之上
//重要性质:
//若i % p = 0,p是素数,那么φ(i * p) = φ(i) * p
//若i % p != 0,p是素数,那么φ(i * p) = φ(i) * (p - 1)
int vis[N];
int prime[N], phi[N];
int sum;

void euler(int n)
{
    memset(vis, 0, sizeof vis);
    int cnt = 0;
    for(int i = 2; i <= n; ++ i){
        if(vis[i] == 0){//如果i是质数
            vis[i] = i;
            prime[ ++ cnt] = i;
            phi[i] = i - 1;
        }
        //给当前的数i乘上一个质因子
        for(int j = 1; j <= cnt ; ++ j){
            if(prime[j] > vis[i] || prime[j] > n / i)break;
            vis[i * prime[j]] = prime[j];//根据性质4,5,p^2 | n -> * (p - 1)
            phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
            if(i % prime[j] == 0)break;
        }
    }
}
    

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i)
    cout << euler_one(i) << " ";
    puts("");
    euler_all(n);
    for(int i = 1; i <= n; ++ i)
        printf("%d ", euler[i]);
    puts("");
    getphi();
    phi[1] = 1;
    for(int i = 1; i <= n; ++ i)
        printf("%d ", phi[i]);
   	puts("");
    return 0;
}

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页