对于欧拉函数的求法最常用的有两方式
- 试除法
- 线性筛法
试除法比较简单,这里就不解释了。
这里主要介绍线性筛法求欧拉函数。
我们先了解什么是欧拉函数:
1
∼
N
中与
N
互质的数的个数被称为欧拉函数,记为
φ
(
N
)
。
1 \sim N 中与 N 互质的数的个数被称为欧拉函数,记为\varphi(N)。
1∼N中与N互质的数的个数被称为欧拉函数,记为φ(N)。
对于一个整数
N
N
N:
- 如果 N N N 为素数的话:那么在小于等于N中,与 N N N 互质的为 1 ∼ N − 1 1 \sim N-1 1∼N−1,就是 N − 1 N-1 N−1;
- 如果 N N N 不为素数的话:那么我们可以用到一个积性函数定理 f ( n ∗ m ) = f ( n ) ∗ f ( m ) f(n * m) = f(n) * f(m) f(n∗m)=f(n)∗f(m),那么就可以进行拆分计算。
那么我们就可以用素数筛的板子,然后进行加入一些语句就可以实现线性筛求欧拉函数。
先说区别区别点吧:
第一个:
if(!used[i])
{
phis[i] = i-1;
primes[++cnt] = i;
}
第一个可以由上述 1 可以解释出来。
第二个:
if(i % primes[j] == 0)
{
phis[i * primes[j]] = primes[j] * phis[i];
break;
}
phis[i * primes[j]] = (primes[j] - 1) * phis[i];
这里就是素数筛的板子,然后加了点东西。
- 第一个语句中:如果
i
m
o
d
p
r
i
m
e
s
[
j
]
i \mod primes[j]
imodprimes[j] 为 0 的话,那么
i
i
i 包括了
m
(
m
=
i
∗
p
r
i
m
e
s
[
j
]
)
m(m = i * primes[j])
m(m=i∗primes[j]) 的所有的质因子,那么
φ
(
m
)
=
p
r
i
m
e
s
[
j
]
∗
φ
(
i
)
\varphi(m) = primes[j] * \varphi(i)
φ(m)=primes[j]∗φ(i)。
证明:因为 i i i 包括了 m m m 的所有质因子,所以 φ ( m ) = m ∗ ∏ k = 1 s ( 1 − 1 p k ) = p r i m e s [ j ] ∗ i ∗ ∏ k = 1 s ( 1 − 1 p k ) = p r i m e s [ j ] ∗ φ ( i ) \varphi(m) = m * \prod_{k=1}^{s}(1-\frac{1}{p_k}) = primes[j] * i * \prod_{k=1}^{s}(1-\frac{1}{p_k}) = primes[j] * \varphi(i) φ(m)=m∗∏k=1s(1−pk1)=primes[j]∗i∗∏k=1s(1−pk1)=primes[j]∗φ(i)。
例如: φ ( 28 ) = 2 ∗ φ ( 14 ) \varphi(28) = 2 * \varphi(14) φ(28)=2∗φ(14)。 - 第二个语句中,如果 i m o d p r i m e s [ j ] i \mod primes[j] imodprimes[j] 不为 0 ,那么两个数互质,又通过上面的性质1得到 φ ( m ) = ( p r i m e s [ j ] − 1 ) ∗ φ ( i ) \varphi(m) = (primes[j]-1) * \varphi(i) φ(m)=(primes[j]−1)∗φ(i)。
下面就是代码环节,结合素数筛更好理解。
对应例题:
洛谷:T349752 筛法求欧拉函数
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int primes[N],used[N],cnt; // 素数筛的变量
int phis[N]; // 定义的是每个整数对应的欧拉值是多少。
void phi(int x)
{
cnt = 0;
phis[1] = 1;
for(int i = 2; i <= x; i++)
{
if(!used[i])
{
phis[i] = i-1;
primes[++cnt] = i;
}
for(int j = 1; i * primes[j] <= x; j++)
{
used[i * primes[j]] = true;
if(i % primes[j] == 0)
{
phis[i * primes[j]] = primes[j] * phis[i];
break;
}
phis[i * primes[j]] = (primes[j] - 1) * phis[i];
}
}
}
void solve()
{
int n;
cin >> n;
phi(n);
long long res = 0;
for(int i =1 ; i <= n; i++)
{
res += phis[i];
}
cout << res << endl;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
// cin >> T;
while(T--)
solve();
return 0;
}