title: 欧拉函数
author: BbiHH
tags:
- ACM_汇总
- ‘’
categories: - 数论
- 欧拉函数
toc: true
date: 2019-07-30 20:46:00
(原创)
定义
- φ(n) 表示
1~n
中 与x
互质的数的个数.
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;
}
(二)筛法求欧拉函数
在线性筛求素数时,每一个合数(非素数)都是被最小的质因子筛掉的.假设p1
是n
的最小质因子, p1 x n' = n
, 那么线性筛过程中,n
通过 n'x p1
筛掉.
下面对 n’mod p1 进行讨论
<1> 如果 n’ mod p1 = 0 那么n'
包含了 n
的所有质因子.即有
<2> 如果 n’mod p1 = 0 ,n
与 n'
互质, 则有
通过对此讨论,可以通过自下而上通过最小质因子求出各数的欧拉函数值,并筛出素数
- 欧拉筛素数
时间复杂度 O(n)
#include <iostream>
#include <cstring>
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<bits/stdc++.h>
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;
}