欧拉函数
要了解欧拉函数,首先得知道剩余系这一概念
完全剩余系
对于非0整数m,以m去除任意整数,可能得到的余数恰有0,1,..,m-1这m个数,这m个数我们就称为一个完全剩余系
简化剩余系
我们只保留完全剩余系中和m互质的数字,其余的删去,剩下的数字就是一个简化剩余系。
如12 , 它的简化剩余系就是1,5 , 7
如7,它的简化剩余系就是1,2,3,4,5,6
欧拉函数
我们把n的简化剩余系元素个数记为φ(n),称为欧拉函数。
欧拉函数的性质(不做证明)
欧拉函数是一个积性函数,故有如下结论:
设m = m1 * m2 ... *mk,m1,.....,mk两两互质,如此则
φ(m) = φ(m1) * φ(m2) *... *φ(mk)
欧拉函数的计算及证明
设n=p1^r1...pk^rk是n的质因数分解式,p1,...,pk 都不同,于是 φ(n) =n * (1 - 1/p1) * (1 - 1/p2) * ... *(1 - 1/pk)
证明:
n有三种情况
情况一:n为质数
则完全剩余系中和n互质的数有n - 1 = n * (1 - 1/n)个,满足上式
情况二:n = p ^ r
(任意整数有唯一质因子乘积表示)
在n的完全剩余系中,和n不互质的数有 p , 1 * p , 2 * p , ....,p^(r - 1) * p
故和p互质的数一共有p ^ r - p ^ (r - 1) = p ^ r * (1 - 1/p )个数字
满足上式
情况三:考虑一般情况 , n=p1^r1...pk^rk,p1,...,pk 都不同
前面提到过欧拉函数的性质
则φ(n) = φ(p1^r1) * ... * φ(pk ^ rk) = p1^r1(1 - 1/p1) ...pk^rk(1 - 1/pk)=n * (1 - 1/p1) * (1 - 1/p2) * ... *(1 - 1/pk)
满足上式
代码实现(C/C++)
int Euler(int n)
{
int ans = n;
for (int i = 2; i <= n / i; i++)//循环条件是因为大于sqrt(n)的质因数最多只有一个
{
if (!(n % i))
ans = ans / i * (i - 1);
while (!(n % i))
{
n /= i;
}
}
//n如果此时大于1,则n为最后一个质因数
if (n > 1)
ans = ans / n * (n - 1);
return ans;
}
线性筛法求欧拉函数
给出给定正整数n,求φ(1) + φ(2) + ... + φ(n),(我们认为1和1互质)
1 <= n <= 1e6
显然暴力枚举的时间复杂度不是我们想要的
这个时候就要联系到之前学过的欧拉筛,也就是线性筛法
这是我们线性筛法求素数的代码
关于线性筛的内容可以看博主另一篇博客素数筛 -- 埃氏筛 欧拉筛 详解-CSDN博客
const int maxn = 1e7 + 10;
int primes[maxn + 1], cnt = 0;//0为素数 1为合数
int prime[maxn + 1];
inline bool isprime(int x)
{
prime[2] = 0;
for (int i = 2; i <= x; i++)
{
if (!prime[i])
primes[cnt++] = i;
for (int j = 0; j < cnt && primes[j] * i <= x; j++)
{
prime[primes[j] * i] = 1;
if (i % primes[j] == 0)
break;
}
}
return !prime[x];
}
我们只需要在代码上稍加改进,
对于i,如果i是质数,那么φ(i) = i - 1,那么其他的数的欧拉函数值该如何去求呢?
我们的线性筛法之所以能求解出给定范围内的所有质数,就说明它把范围内的所有数字都筛了一遍
对于合数,我们应该在其被筛的地方根据我们已知的欧拉函数的性质来求出该合数的欧拉函数值
我们先给出结论
if (i % primes[j] == 0)
{
phi[i * primes[j]] = primes[j] * phi[i];
break;
}
else
{
phi[i * primes[j]] = (primes[j] - 1) * phi[i];
}
对于else中的语句是最好理解的,我们知道欧拉函数的性质,此时primes[j]和i互质,那么由性质得出phi[i * primes[j]] = (primes[j]- 1) * phi[i];
但是对于if内的语句又是如何解释呢?
我们这得回到线性筛法的原理,我们保证每个合数被其最小质因数筛去
对于合数m = primes[j] * i
如果 i % primes[j] == 0,说明primes[j]也是i的因数,那么此时m的质因数和我们i的质因数相同了,这也就是我们线性筛在此处break能保证合数能被其最小质因数筛去
那么这个时候的欧拉函数值是什么呢?
根据公式有 phi[primes[j] * i] = primes[j] * i * (1 - 1/p1) ...(1 - 1/pk) = primes[j] * phi[i],(因为m和i质因数一样)
这就是递推的由来
完整代码如下:
const int maxn = 1e6 + 7;
int primes[maxn + 1], cnt = 0; // 0为素数 1为合数
bitset<maxn> isprime;
vector<int> phi(maxn + 1);
inline void Euler_Phi(int x)
{
isprime[2] = 0;
phi[1] = 1;
for (int i = 2; i <= x; i++)
{
if (!isprime[i])
{
primes[cnt++] = i;
phi[i] = i - 1;
}
for (int j = 0; j < cnt && primes[j] * i <= x; j++)
{
isprime[primes[j] * i] = 1;
if (i % primes[j] == 0)
{
phi[i * primes[j]] = primes[j] * phi[i];
break;
}
else
{
phi[i * primes[j]] = (primes[j] - 1) * phi[i];
}
}
}
}
费马-欧拉定理
若a和n互质,则
a^φ(n) ≡ 1 (mod n)
若n=p是一个质数,则φ(n) =p-1,故得如下推论.
推论:费马小定理I
若p 是质数而p卜a,则
a ^ (p - 1) ≡ 1 (mod p)
费马小定理常常被表示成另一种形式,也是经常用到的.
推论 费马小定理II
若p为质数,则对任意整数a都有
a ^ p ≡ p (mod p)