Part 1:前置知识
线性筛
#include<bits/stdc++.h>
using namespace std;
const int N=100001;
int n,v[N],prime[N],tot;
void primes(int n)
{
for(int i=2; i<=n; i++)
{
if(!v[i])
{
v[i]=i;
prime[++tot]=i;
}
for(int j=1; j<=tot; j++)
{
if(prime[j]>v[i] || prime[j]>n/i)
break;
v[i*prime[j]]=prime[j];
}
}
}
int main()
{
cin>>n;
primes(n);
for(int i=1; i<=tot; i++)
cout<<prime[i]<<" ";
return 0;
}
Part 2:欧拉函数
- 定义:欧拉函数 φ ( n ) φ(n) φ(n) 表示小于等于 n n n,且与 n n n 互质的正整数的个数。
- 公式:
若在算数基本定理中, n = p 1 c 1 p 2 c 2 . . . p m c m n=p_1^{c_1}p_2^{c_2}...p_m^{c_m} n=p1c1p2c2...pmcm( p p p 为质数),则由容斥原理: φ ( n ) = n ∗ p 1 − 1 p 1 ∗ p 2 − 2 p 2 ∗ . . . ∗ p m − m p m = n ∗ ∏ p ∣ n ( 1 − 1 p ) φ(n)=n*\dfrac{p_1-1}{p_1}*\dfrac{p_2-2}{p_2}*...*\dfrac{p_m-m}{p_m}=n*\prod\limits_{p\mid{n}}{(1-\dfrac{1}{p})} φ(n)=n∗p1p1−1∗p2p2−2∗...∗pmpm−m=n∗p∣n∏(1−p1)
关于此公式的证明,读者可自行推导
Part 3:积性函数
- 定义:若一个定义在正整数域上的函数 f f f,当 x , y x,y x,y 互质时,有 f ( x y ) = f ( x ) ∗ f ( y ) f(xy)=f(x)*f(y) f(xy)=f(x)∗f(y),则称函数 f f f 是积性函数
- 欧拉函数是积性函数,即:若 a , b a,b a,b 互质,则 φ ( a b ) = φ ( a ) ∗ φ ( b ) φ(ab)=φ(a)*φ(b) φ(ab)=φ(a)∗φ(b)
证明:由欧拉函数计算公式可得
- 若 d ( n ) d(n) d(n) 表示 n n n 的约数个数,则 d ( n ) d(n) d(n) 是积性函数
- 若 s ( n ) s(n) s(n) 表示 n n n 所有约数的和,则 s ( n ) s(n) s(n) 是积性函数
- 所有的积性函数都可以用线性筛求解!!!
Part 4:欧拉函数常见的性质
- 若 n n n 是质数,则 φ ( n ) = n − 1 φ(n)=n-1 φ(n)=n−1
- 若 n = p k n=p^k n=pk,且 p p p 为质数,则 φ ( n ) = ( p − 1 ) ∗ p k − 1 φ(n)=(p-1)*p^{k-1} φ(n)=(p−1)∗pk−1
- 若 p p p 是质数,且 { p ∣ n ⇒ φ ( n q ) = φ ( n ) ∗ q p ∤ n ⇒ φ ( n q ) = φ ( n ) ∗ ( q − 1 ) \begin{cases}p\mid{n}&\Rightarrowφ(nq)=φ(n)*q\\p\nmid{n}&\Rightarrowφ(nq)=φ(n)*(q-1)\end{cases} { p∣np∤n⇒φ(nq)=φ(n)∗q⇒φ(nq)=φ(n)∗(q−1)
- n = ∑ d ∣ n φ ( d ) n=\sum\limits_{d\mid{n}}{φ(d)} n=d∣n∑φ(d)
- φ ( a b ) = φ ( a ) ∗ φ ( b ) ∗ d φ ( d ) φ(ab)=φ(a)*φ(b)*\frac{d}{φ(d)} φ(ab)=φ(a)∗φ(b)∗φ(d)d,其中 d = gcd ( a , b ) d=\gcd(a,b) d=gcd(a,b)
Part 5:例题
【模板题】求 φ(n)
解题思路
- 我们已知 φ ( n ) φ(n) φ(n) 的计算公式,所以只需对 n n n 进行质因数分解即可
代码
#include<bits/stdc++.h>
using namespace std;
const int N=100001;
int n;
int GetPhi(int n)
{
int ans=n;
for(int i=2; i*i<=n; i++) //分解质因数
{
if(n%i==0)
{
ans=ans*(i-1)/i; //计算公式
while(n%i==0)
n/=i;
}
}
if(n>1) //还剩下一个较大的质数
ans=ans*(n-1)/n;
return ans;
}
int main()
{
cin>>n;
cout<<GetPhi(n);
return 0;
}
【模板题】求 φ(1) ~ φ(n)
解题思路
- 由于欧拉函数是积性函数,所以我们考虑用线性筛求解
- 从欧拉函数性质 3 3 3 出发,在线性筛中,每个合数 x x x 都会被它最小的质因子 p p p 筛去,此时我们就可以用 p p p ( ( (或 p − 1 ) p-1) p−1) 和 φ ( x / p ) φ(x/p) φ(x/p) 来推出 φ ( x ) φ(x) φ(x) ,具体是 p p p 还是 p − 1 p-1 p−1,要看 x / p x/p x/p,即我们外层循环的 i i i 是否是 q q q 的倍数;而对于每个质数 y y y,由性质 1 1 1<