欧拉函数与筛法求欧拉函数

目录

  • 欧拉函数
    • 欧拉函数的定义
    • 欧拉函数的公式
    • 欧拉函数的公式推导
    • 欧拉定理
    • 典型例题
    • 代码实现
  • 筛法求欧拉函数
    • 思路分析
    • 经典例题
    • 代码实现


欧拉函数

欧拉函数的定义

对于任意正整数 n n n,欧拉函数 φ ( n ) φ(n) φ(n) 表示小于或等于 n n n 的正整数中,与 n n n 互质的正整数个数。

例如:

  • φ ( 1 ) = 1 φ(1) = 1 φ(1)=1,因为 1 1 1 只与 1 1 1 互质。
  • φ ( 6 ) = 2 φ(6) = 2 φ(6)=2,因为与6互质的数有 1 1 1 和 $5,共 2 2 2 个。
  • φ ( 10 ) = 4 φ(10) = 4 φ(10)=4,因为与10互质的数有 1 、 3 、 7 1、3、7 137 9 9 9,共 4 4 4 个。

欧拉函数的公式

对于任意正整数 n n n φ ( n ) = n ∗ ( 1 − 1 P 1 ) ∗ ( 1 − 1 P 2 ) ∗ . . . ∗ ( 1 − 1 P k ) φ(n) = n * (1 - \frac{1}{P_1}) * (1 - \frac{1}{P_2}) * ... * (1 - \frac{1}{P_k}) φ(n)=n(1P11)(1P21)...(1Pk1),其中, P 1 , P 2 , . . . , P k P_1, P_2, ..., P_k P1,P2,...,Pk n n n 的不同的质因数。

欧拉函数公式,只与因子相关,与指数无关。

例如:
φ ( 10 ) = 10 ∗ ( 1 − 1 2 ) ∗ ( 1 − 1 5 ) = 4 φ(10) = 10 * (1 - \frac{1}{2}) * (1 - \frac{1}{5}) = 4 φ(10)=10(121)(151)=4
φ ( 15 ) = 15 ∗ ( 1 − 1 3 ) ∗ ( 1 − 1 5 ) = 8 φ(15) = 15 * (1 - \frac{1}{3}) * (1 - \frac{1}{5}) = 8 φ(15)=15(131)(151)=8


欧拉函数的公式推导

利用容斥原理的推导过程:

对数字N进行质因数分解,可得
N = P 1 r 1 ∗ P 2 r 2 ∗ P 3 r 3 ∗ . . . ∗ P k r k N=P_1^{r_1}*P_2^{r_2}*P_3^{r_3}*...*P_k^{r_k} N=P1r1P2r2P3r3...Pkrk

由于不能与 N N N 不互质,所以 1 1 1 ~ N N N 不可包含 P 1 , P 2 , . . . , P k P_1,P_2,...,P_k P1,P2,...,Pk 这些质因子。

P 1 , P 2 , . . . , P k P_1,P_2,...,P_k P1,P2,...,Pk 的倍数都减去,分别减去 N P 1 , N P 2 , . . . , N P k \frac{N}{P_1},\frac{N}{P_2},...,\frac{N}{P_k} P1N,P2N,...,PkN 个。

如图所示:
欧拉函数与筛法求欧拉函数_第1张图片

但是由于 P 1 , P 2 , . . . , P k P_1,P_2,...,P_k P1,P2,...,Pk 不同质因子的倍数可能会出现重复,有些数重叠的数会被多次减去。如图中重叠部分会被多次相减,因此要补上重叠的数。比如某个数,是 P 2 P_2 P2 的倍数,也是 P 3 P_3 P3 的倍数,就减了两回,还需要再加回来 P 2 ∗ P 3 P_2∗P_3 P2P3 的倍数,换做是其他的组合就是 N P 1 ∗ P 2 , N P 1 ∗ P P 3 , . . . , N P 1 ∗ P k , . . \frac{N}{P_1*P_2},\frac{N}{P_1*P_P3},...,\frac{N}{P_1*P_k},.. P1P2N,P1PP3N,...,P1PkN,..

但是更多质因子重叠的部分又会弥补至减去之前的状态,得继续减去。如 P 1 ∗ P 2 ∗ P 3 P_1*P_2*P_3 P1P2P3这样的更多质因子重叠的部分,而后就像之前一样一减一加最终推出结果。

φ ( N ) = N ∗ ( 1 − 1 P 1 ) ∗ ( 1 − 1 P 2 ) ∗ . . . ∗ ( 1 − 1 P k ) φ(N) = N * (1 - \frac{1}{P_1}) * (1 - \frac{1}{P_2}) * ... * (1 - \frac{1}{P_k}) φ(N)=N(1P11)(1P21)...(1Pk1)


欧拉定理

如果 a a a n n n 是正整数,且 a a a n n n 互质,则 a φ ( n ) ≡ 1 ( m o d    n ) a^{φ(n)} ≡ 1 (\mod n) aφ(n)1(modn)
如果 n n n 为质数,则 a n − 1 ≡ 1 ( m o d    n ) a^{n-1} ≡ 1 (\mod n) an11(modn)


典型例题

题目描述:
给定 n 个正整数 ai,请你求出每个数的欧拉函数。

输入格式:
第一行包含整数 n。

接下来 n 行,每行包含一个正整数 ai。

输出格式:
输出共 n 行,每行输出一个正整数 ai 的欧拉函数。

数据范围:
1 ≤ n ≤ 100 , 1 ≤ a i ≤ 2 × 1 0 9 1≤n≤100,1≤a_i≤2×10^9 1n100,1ai2×109

输入样例:

3
3
6
8

输出样例:

2
2
4

代码实现

res对不同的质数只需计算一次,不要将res的计算放到循环中。
res计算过程中要避免出现小数的情况,将除法提前与大数进行。

#define _CRT_NO_SECURE_WARNINGS
#include

using namespace std;

int phi(int x)
{
	int res = x;
	for (int i = 2; i <= x / i; ++i)
	{
		if (x % i) continue;
		
		// res对不同的质数只需计算一次,不要将res的计算放到循环中
		res = res / i * (i - 1); // 注意避免出现小数情况

		while (x % i == 0) x /= i;
	}
	if (x > 1) res = res / x * (x - 1);
	return res;
}
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int a;
		cin >> a;
		cout << phi(a) << endl;
	}
	return 0;
}

筛法求欧拉函数

思路分析

  • 如果这个数是质数,那么对质数 i i i 的欧拉函数值是 p h i [ i ] = i − 1 phi[i]=i−1 phi[i]=i1
  • 如果 i i i % p r i m e s [ j ] = = 0 primes[j] == 0 primes[j]==0,那么 p h i [ i ∗ p r i m e s [ j ] ] = p h i [ i ] × p r i m e s [ j ] phi[i*primes[j]]=phi[i]×primes[j] phi[iprimes[j]]=phi[i]×primes[j]。(相当于 i i i 中的质因子包括了 p r i m e s [ j ] primes[j] primes[j]
  • 如果 i i i % p r i m e s [ j ] primes[j] primes[j] ! = 0 != 0 !=0,那么 p h i [ i ∗ p r i m e s [ j ] ] = p h i [ i ] × ( p r i m e s [ j ] − 1 ) phi[i*primes[j]]=phi[i]×(primes[j] - 1) phi[iprimes[j]]=phi[i]×(primes[j]1)。(通过公式变形得来)

经典例题

题目描述:
给定一个正整数 n n n,求 1 1 1 ~ n n n 中每个数的欧拉函数之和。

输入格式:
共一行,包含一个整数 n n n

输出格式:
共一行,包含一个整数,表示 1 1 1 ~ n n n 中每个数的欧拉函数之和。

数据范围:
1 < n < 1 0 6 11<n<106

输入样例:

6

输出样例:

12

代码实现

#define _CRT_NO_SECURE_WARNINGS
#include

using namespace std;

const int N = 1e6 + 10;
int phi[N], primes[N], cnt;
bool st[N];
void get_eulers(int n)
{
	for (int i = 2; i <= n; ++i)
	{
		phi[1] = 1;
		if (!st[i])
		{
			phi[i] = i - 1;
			primes[cnt++] = i;
		}
		for (int j = 0; primes[j] <= n / i; ++j)
		{
			st[primes[j] * i] = true;
			if (i % primes[j] == 0)
			{
				phi[primes[j] * i] = phi[i] * primes[j];
				break;
			}
			phi[primes[j] * i] = phi[i] * (primes[j] - 1);
		}
	}
}
int main()
{
	int n, res = 0;
	cin >> n;
	get_eulers(n);
	for (int i = 1; i <= n; ++i) res += phi[i];
	cout << res << endl;
	return 0;
}

你可能感兴趣的:(从零开始的算法打灰,算法,c++)