欧拉函数
一、定义
对于正整数 n n n,在小于 n n n 的正整数中与 n n n 互质的数的数目是欧拉函数,记作 φ ( n ) \varphi(n) φ(n)。
二、性质
性质一
根据定义,我们可以得出公式:
φ ( n ) = ∑ i = 1 n − 1 [ gcd ( i , n ) = 1 ] \varphi(n)=\sum_{i=1}^{n-1}[\gcd(i,n)=1] φ(n)=i=1∑n−1[gcd(i,n)=1]
性质二
φ ( n ) = n ∏ p ∣ n p ∈ P ( 1 − 1 p ) \varphi(n)=n\prod_{\substack{p|n\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right) φ(n)=np∣np∈P∏(1−p1)
其中, P \mathbb{P} P 为质数集。
下面证明该性质:
如果 p p p 是 n n n 质因数,那么有 1 p \frac{1}{p} p1 的数是 p p p 的倍数, 即有 ( 1 − 1 p ) \left(1-\frac{1}{p}\right) (1−p1) 的数与 n n n 互质,那么与 n n n 的质因数均不相等的数的个数就是 n ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) . . . ( 1 − 1 p k ) n\left(1-\frac{1}{p_1}\right)\left(1-\frac{1}{p_2}\right)...\left(1-\frac{1}{p_k}\right) n(1−p11)(1−p21)...(1−pk1),得证。
性质三
如果 n n n 是质数,小于等于 n n n 的数均与 n n n 互质,那么有 φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n−1。
性质四
如果 n n n 与 m m m 互质,那么有
φ ( n m ) = φ ( n ) φ ( m ) \varphi(nm)=\varphi(n)\varphi(m) φ(nm)=φ(n)φ(m)
下面证明该性质:
φ ( n ) φ ( m ) = n ∏ p ∣ n p ∈ P ( 1 − 1 p ) m ∏ p ∣ m p ∈ P ( 1 − 1 p ) = n m ∏ p ∣ n p ∈ P ( 1 − 1 p ) ∏ p ∣ m p ∈ P ( 1 − 1 p ) \varphi(n)\varphi(m)=n\prod_{\substack{p|n\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right)m\prod_{\substack{p|m\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right)=nm\prod_{\substack{p|n\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right)\prod_{\substack{p|m\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right) φ(n)φ(m)=np∣np∈P∏(1−p1)mp∣mp∈P∏(1−p1)=nmp∣np∈P∏(1−p1)p∣mp∈P∏(1−p1)
因为 n n n 和 m m m 互质,所以 n m nm nm 的质因数就是 n n n 的质因数与 m m m 的质因数的交集,所以
φ ( n ) φ ( m ) = n m ∏ p ∣ n m p ∈ P ( 1 − 1 p ) = φ ( n m ) \varphi(n)\varphi(m)=nm\prod_{\substack{p|nm\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right)=\varphi(nm) φ(n)φ(m)=nmp∣nmp∈P∏(1−p1)=φ(nm)
性质五
当 n > 2 n>2 n>2 时, φ ( n ) \varphi(n) φ(n) 是偶数。
下面证明该性质:
当 gcd ( n , i ) = 1 \gcd(n,i)=1 gcd(n,i)=1 时, gcd ( n , n − i ) = 1 \gcd(n,n-i)=1 gcd(n,n−i)=1。
若 i = n − i i=n-i i=n−i,则 n = 2 i n=2i n=2i, n n n 与 i i i 不互质。
所以 φ ( n ) \varphi(n) φ(n) 总为偶数。( n > 2 n>2 n>2)
性质六
在区间 [ 1 , n ] [1,n] [1,n] 中所有与 n n n 互质的数的和为 φ ( n ) n 2 \frac{\varphi(n)n}{2} 2φ(n)n
下面证明该性质:
根据性质五,如果 gcd ( n , i ) = 1 \gcd(n,i)=1 gcd(n,i)=1,那么有 gcd ( n , n − i ) = 1 \gcd(n,n-i)=1 gcd(n,n−i)=1, i i i 和 n − i n-i n−i 的和是 n n n,这样的数对的个数是 φ ( n ) 2 \frac{\varphi(n)}{2} 2φ(n) 个,所以和为 φ ( n ) n 2 \frac{\varphi(n)n}{2} 2φ(n)n。
性质七
φ ( n 2 ) = n φ ( n ) \varphi(n^2)=n\varphi(n) φ(n2)=nφ(n)
下面证明该性质:
因为 n 2 n^2 n2 的质因数和 n n n 的质因数相同,因此
φ ( n 2 ) = n 2 ∏ p ∣ n 2 p ∈ P ( 1 − 1 p ) = n 2 ∏ p ∣ n p ∈ P ( 1 − 1 p ) = n × n ∏ p ∣ n p ∈ P ( 1 − 1 p ) = n φ ( n ) \varphi(n^2)=n^2\prod_{\substack{p|n^2\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right)=n^2\prod_{\substack{p|n\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right)=n\times n\prod_{\substack{p|n\\p\in\mathbb{P}}}\left(1-\frac{1}{p}\right)=n\varphi(n) φ(n2)=n2p∣n2p∈P∏(1−p1)=n2p∣np∈P∏(1−p1)=n×np∣np∈P∏(1−p1)=nφ(n)
三、求欧拉函数
快速求欧拉函数
根据性质二,我们可以在 O ( n ) O(\sqrt{n}) O(n) 的时间复杂度内完成。
代码如下:
void phi(int n)
{
int ans = n;
for (int i = 2; i <= n / i; i ++ )
if (n % i == 0)
{
ans = ans / i * (i - 1);
while (n % i == 0)
n /= i;
}
if (n > 1)
ans = ans / n * (n - 1);
return ans;
}
线性求欧拉函数
根据性质三、性质四和性质七,我们就可以线性求欧拉函数。
- 如果 n n n 为质数,那么 φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n−1。
- 如果 m m m 为 n n n 的最小平方因子,那么 φ ( n ) = m φ ( n m ) \varphi(n)=m\varphi(\frac{n}{m}) φ(n)=mφ(mn)
- 如果 m m m 为 n n n 的最小质因数,那么 φ ( n ) = φ ( m ) φ ( n m ) = ( m − 1 ) φ ( n m ) \varphi(n)=\varphi(m)\varphi(\frac{n}{m})=(m-1)\varphi(\frac{n}{m}) φ(n)=φ(m)φ(mn)=(m−1)φ(mn)。
以下是一个可以参考的代码:
phi[1] = 1;
for (int i = 2; i <= n; i ++ )
{
if (!vis[i])
{
prime[ ++ cnt] = i;
phi[i] = i - 1;
}
for (int j = 1; prime[j] <= n / i; j ++ )
{
vis[i * prime[j]] = 1;
if (i % prime[j] == 0)
{
phi[i * prime[j]] = prime[j] * phi[i];
break;
}
phi[i * prime[j]] = (prime[j] - 1) * phi[i];
}
}
四、例题
P2158 [SDOI2008] 仪仗队
我们假设坐标的下标从 0 0 0 开始。
设一个人的位置是 ( x , y ) (x,y) (x,y) ,若 g c d ( x , y ) = k ≠ 1 gcd(x,y)=k\not=1 gcd(x,y)=k=1,那么在坐标 ( x k , y k ) (\frac{x}{k},\frac{y}{k}) (kx,ky) 的人会将这个人遮挡,所以这道题其实就是在求 gcd ( x , y ) = 1 \gcd(x,y)=1 gcd(x,y)=1 的个数,公式如下:
∑ i = 0 n − 1 ∑ j = 0 n − 1 [ gcd ( i , j ) = 1 ] \sum_{i=0}^{n-1}\sum_{j=0}^{n-1}[\gcd(i,j)=1] i=0∑n−1j=0∑n−1[gcd(i,j)=1]
通过观察图片可以发现,图片延 y = x y=x y=x 对称,所以原式
= ∑ i = 0 n − 1 ∑ j = 0 i − 1 [ gcd ( i , j ) = 1 ] + ∑ i = 0 n − 1 ∑ j = i i [ gcd ( i , j ) = 1 ] + ∑ i = 0 n − 1 ∑ j = i + 1 n − 1 [ gcd ( i , j ) = 1 ] =\sum_{i=0}^{n-1}\sum_{j=0}^{i-1}[\gcd(i,j)=1]+\sum_{i=0}^{n-1}\sum_{j=i}^{i}[\gcd(i,j)=1]+\sum_{i=0}^{n-1}\sum_{j=i+1}^{n-1}[\gcd(i,j)=1] =i=0∑n−1j=0∑i−1[gcd(i,j)=1]+i=0∑n−1j=i∑i[gcd(i,j)=1]+i=0∑n−1j=i+1∑n−1[gcd(i,j)=1]
= 2 ∑ i = 0 n − 1 ∑ j = 0 i − 1 [ gcd ( i , j ) = 1 ] + 1 =2\sum_{i=0}^{n-1}\sum_{j=0}^{i-1}[\gcd(i,j)=1]+1 =2i=0∑n−1j=0∑i−1[gcd(i,j)=1]+1
= 2 ∑ i = 1 n − 1 φ ( i ) + 1 =2\sum_{i=1}^{n-1}\varphi(i)+1 =2i=1∑n−1φ(i)+1
需要注意,当 n = 1 n=1 n=1 时,答案为 0 0 0。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
int n;
long long prime[N], vis[N], phi[N], cnt;
int main()
{
scanf("%d", &n);
if (n == 1)
{
puts("0");
return 0;
}
phi[1] = 1;
for (int i = 2; i <= n; i ++ )
{
if (!vis[i])
{
prime[ ++ cnt] = i;
phi[i] = i - 1;
}
for (int j = 1; prime[j] <= n / i; j ++ )
{
vis[i * prime[j]] = 1;
if (i % prime[j] == 0)
{
phi[i * prime[j]] = prime[j] * phi[i];
break;
}
phi[i * prime[j]] = (prime[j] - 1) * phi[i];
}
}
long long ans = 0;
for (int i = 1; i < n; i ++ )
ans += phi[i];
printf("%d\n", 2 * ans + 1);
return 0;
}
P2568 GCD
枚举每一个质数 p p p,求 gcd ( x , y ) = p \gcd(x,y)=p gcd(x,y)=p 的情况,此时一定有 p ∣ x p|x p∣x, p ∣ y p|y p∣y,那么 gcd ( x , y ) = p \gcd(x,y)=p gcd(x,y)=p 等价于 gcd ( x p , y p ) = 1 \gcd(\frac{x}{p},\frac{y}{p})=1 gcd(px,py)=1,于是就有公式:
∑ p ∈ P ∑ i = 1 n ∑ j = 1 n [ gcd ( i , j ) = p ] \sum_{p\in\mathbb{P}}\sum_{i=1}^{n}\sum_{j=1}^{n}[\gcd(i,j)=p] p∈P∑i=1∑nj=1∑n[gcd(i,j)=p]
= ∑ p ∈ P ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 ⌊ n p ⌋ [ gcd ( i , j ) = 1 ] =\sum_{p\in\mathbb{P}}\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{n}{p}\right\rfloor}[\gcd(i,j)=1] =p∈P∑i=1∑⌊pn⌋j=1∑⌊pn⌋[gcd(i,j)=1]
= ∑ p ∈ P ( ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 i − 1 [ gcd ( i , j ) = 1 ] + ∑ i = 1 ⌊ n p ⌋ ∑ j = i i [ gcd ( i , j ) = 1 ] + ∑ i = 1 ⌊ n p ⌋ ∑ j = i + 1 ⌊ n p ⌋ [ gcd ( i , j ) = 1 ] ) =\sum_{p\in\mathbb{P}}\left(\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=1}^{i-1}[\gcd(i,j)=1]+\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=i}^{i}[\gcd(i,j)=1]+\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=i+1}^{\left\lfloor\frac{n}{p}\right\rfloor}[\gcd(i,j)=1]\right) =p∈P∑ i=1∑⌊pn⌋j=1∑i−1[gcd(i,j)=1]+i=1∑⌊pn⌋j=i∑i[gcd(i,j)=1]+i=1∑⌊pn⌋j=i+1∑⌊pn⌋[gcd(i,j)=1]
= ∑ p ∈ P ( 2 ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 i − 1 [ gcd ( i , j ) = 1 ] + 1 ) =\sum_{p\in\mathbb{P}}\left(2\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=1}^{i-1}[\gcd(i,j)=1]+1\right) =p∈P∑ 2i=1∑⌊pn⌋j=1∑i−1[gcd(i,j)=1]+1
= ∑ p ∈ P [ 2 ∑ i = 1 ⌊ n p ⌋ ( φ ( i ) − 1 ) + 1 ] =\sum_{p\in\mathbb{P}}\left[2\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}(\varphi(i)-1)+1\right] =p∈P∑ 2i=1∑⌊pn⌋(φ(i)−1)+1
= ∑ p ∈ P ( 2 ∑ i = 1 ⌊ n p ⌋ φ ( i ) − 1 ) =\sum_{p\in\mathbb{P}}\left(2\sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\varphi(i)-1\right) =p∈P∑ 2i=1∑⌊pn⌋φ(i)−1
对于倒数第 2 2 2 个式子,由于与 1 1 1 互质的数的个数 0 0 0 但 φ ( 1 ) = 1 \varphi(1)=1 φ(1)=1,需要减 1 1 1。
#include <bits/stdc++.h>
using namespace std;
const int N = 10000005;
int n;
long long prime[N], vis[N], phi[N], Phi[N], cnt;
int main()
{
scanf("%d",n);
phi[1] = 1;
for(int i = 2; i <= n; i ++ )
{
if(!vis[i])
{
prime[ ++ cnt] = i;
phi[i] = i - 1;
}
for(int j = 1; prime[j] <= n / i; j ++ )
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0)
{
phi[i * prime[j]] = prime[j] * phi[i];
break;
}
phi[i * prime[j]] = (prime[j] - 1) * phi[i];
}
}
long long ans = 0;
for(int i = 1; i < n; i ++ )
{
Phi[i] = Phi[i - 1] + phi[i];
}
for(int i = 1; i <= cnt; i ++ )
{
ans += 2 * Phi[n / prime[i]] - 1;
}
printf("%d\n", ans);
return 0;
}