欧拉函数介绍与使用 c++

title: 欧拉函数
author: BbiHH
tags:

  • ACM_汇总
  • ‘’
    categories:
  • 数论
  • 欧拉函数
    toc: true
    date: 2019-07-30 20:46:00

(原创)

定义

  • φ(n) 表示 1~n 中 与 x 互质的数的个数.

    欧拉函数介绍与使用 c++_第1张图片
    pi即为n的质因子.
    oi-wiki

性质

  • n = p^k ,其中p为质数,那么φ(n)=p^k-p^(k-1) (定义推出)

  • 它在整数n上的值等于对n进行素因子分解后,所有的素数幂上的欧拉函数之积 (定义推出)

  • 欧拉函数是积性函数当 gcd(a,b)=1 时, φ(a*b) = φ(a)*φ(b) , 特别的 , 当 n 为奇数时,φ(2n) = φ(n)

求欧拉函数

(一)直接实现

求解欧拉函数的值可用其计算公式 φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn) 通过找x的质因子来计算其欧拉函数

时间复杂度: O(√¯n) 用于求单个数的欧拉函数值

int euler_phi(int n)
{
  int ans = n;
  for (int i = 2; i*i <= n; i++) //只需要枚举到 sqrt(n) 
    if (n % i == 0) {
      ans = ans / i * (i - 1);
      while (n % i == 0) n /= i; //把该质因子全部约掉
    }
  if (n > 1) ans = ans / n * (n - 1); //当n还大于零时,其为一个素数,质因子为其本身
  return ans;
}
(二)筛法求欧拉函数

在线性筛求素数时,每一个合数(非素数)都是被最小的质因子筛掉的.假设p1n的最小质因子, p1 x n' = n , 那么线性筛过程中,n通过 n'x p1 筛掉.

下面对 n’mod p1 进行讨论

<1> 如果 n’ mod p1 = 0 那么n'包含了 n 的所有质因子.即有

欧拉函数介绍与使用 c++_第2张图片


<2> 如果 n’mod p1 = 0 ,nn' 互质, 则有

在这里插入图片描述

通过对此讨论,可以通过自下而上通过最小质因子求出各数的欧拉函数值,并筛出素数

  • 欧拉筛素数

时间复杂度 O(n)

#include 
#include 
using namespace std;

const int MAXN = 1e6+5;

bool flag[MAXN];    //标记数组
int phi[MAXN];      //欧拉函数值,i的欧拉函数值=phi[i]
int p[MAXN];        //素数
int cnt = 0;        //素数个数

void Get_phi()      //筛法求欧拉函数,且线性求出素数
{
    cnt = 0;
    memset(flag, true, sizeof(flag));
    phi[1] = 1;
    for(int i=2; i<MAXN; i++)                     //线性筛法
    {
        if(flag[i])///素数
        {
            p[cnt++] = i;
            phi[i] = i-1;                         //素数的欧拉函数值是素数 n-1
        }
        for(int j=0; j<cnt; j++)
        {
            if(i*p[j] > MAXN)
                break;
            flag[i*p[j]] = false;                 //素数的倍数,所以i*p[j]不是素数
            if(i%p[j] == 0)                       //性质:i mod p == 0, 那么 phi(i * p) == p * phi(i)
            {
                phi[i*p[j]] = p[j] * phi[i];
                break;
            }
            else
                phi[i*p[j]] = (p[j]-1) * phi[i];  //i mod p != 0, 那么 phi(i * p) == phi(i) * (p-1) 
        }
    }
}

//测试
int main()
{
    Get_phi();
    int m;
    while(cin>>m)
    {
        cout<<phi[m]<<endl;
    }
    return 0;
}
  • 求欧拉函数

时间复杂度 O(n)

void phi_table(int n,int *phi)
{
     memset(phi,0,sizeof(phi)); //初始化
     phi[1] = 1;
     for(int i=2;i<=n;i++){
        if(phi[i]==0){               // phi[i]==0 说明当前i为素数  因为在下面的向上递推的时候给i的倍数
            for(int j=i;j<=n;j+=i){  // 没赋值的都不为i的倍数, 参考挨氏素数筛法
                 if(phi[j]==0) phi[j] = j; 
                 phi[j] = phi[j] / i * (i - 1) ;  //递归地使用公式 此时 i 为 j 一个的质因子,第一个出现
                    }                             //的 i 也为其最小质因子
             }
        }
}
  • 埃氏筛法筛素数(线性筛)

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

#include
using namespace std;

typedef long long int LL;
const int MAXN = 1e5+7;
int is_prime[MAXN];
int prime[MAXN];

//埃氏筛法  return 素数个数
int Eratosthenes(int n)
{
        int p = 0;
        for(int i=0;i<=n;++i) is_prime[i] = 1;
        is_prime[0] = is_prime[1] = 0;
        for(int i=2;i<=n;++i){
                if(is_prime[i]){
                        prime[p++] = i;
                        for(int j=i;j<=n;j+=i)
                                is_prime[j] = 0;
                }
        }
        return p;
}


你可能感兴趣的:(ACM摸鱼)