互质与欧拉函数
互质
任意自然数 a , b a,b a,b,若 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,则称 a , b a,b a,b 互质。
对于三个数或更多个数,将 g c d ( a , b , c ) = 1 gcd(a,b,c)=1 gcd(a,b,c)=1 的情况称为 a , b , c a,b,c a,b,c 互质。把 g c d ( a , b ) = g c d ( b , c ) = g c d ( a , c ) = 1 gcd(a,b)=gcd(b,c)=gcd(a,c)=1 gcd(a,b)=gcd(b,c)=gcd(a,c)=1 称为两两互质,两者有明显的区别,显然,后者要求更高。
欧拉函数
1 ∼ N 1\sim N 1∼N 中与 N N N 互质的个数被称为欧拉函数,记为 φ ( N ) \varphi(N) φ(N) 。
在算术基本定理中, N = p 1 c 1 × p 2 c 2 × . . . × p m c m N=p_1^{c_1}\times p_2^{c_2}\times ...\times p_m^{c_m} N=p1c1×p2c2×...×pmcm, p 1 , p 2 . . . p m p_1,p_2...p_m p1,p2...pm 为质数,则:
φ ( N ) = N × p 1 − 1 p 1 × p 2 − 1 p 2 × . . . × p m − 1 p m \varphi(N)=N\times \frac {p_1-1} {p_1}\times \frac {p_2-1} {p_2}\times...\times \frac {p_m-1} {p_m} φ(N)=N×p1p1−1×p2p2−1×...×pmpm−1
证明:
若 p p p 是 N N N 的质因子,则 1 ∼ N 1\sim N 1∼N 中 p p p 的倍数有: p , 2 p , 3 p . . . ( N p ) × p p,2p,3p...(\frac N p)\times p p,2p,3p...(pN)×p,共 N p \frac N p pN (整除)个。同理,若 q q q 也是 N N N 的质因子,则 1 ∼ N 1\sim N 1∼N 中 q q q 的倍数有: q , 2 q , 3 q . . . ( N q ) × q q,2q,3q...(\frac N q)\times q q,2q,3q...(qN)×q,共 N q \frac N q qN (整除)个。同时 p × q p\times q p×q 的倍数即被 p p p 排除了,又被 q q q 排除了,所有需要加回来。因此, 1 ∼ N 1\sim N 1∼N 中不与 N N N 含有共同质因子 p p p 和 q q q 的个数为:
N − N q − N p + N p q = N × ( 1 − 1 p − 1 q + 1 p q ) = N × ( 1 − 1 p ) × ( 1 − 1 q ) N-{\frac N q}-{\frac N p}+{\frac N {pq}}=N\times (1-\frac 1 p-\frac 1 q+\frac 1 {pq})=N\times (1-\frac 1 p)\times (1-\frac 1 q) N−qN−pN+pqN=N×(1−p1−q1+pq1)=N×(1−p1)×(1−q1)
这种思想被称为容斥思想(后续会学习)。同理,可以得到 1 ∼ N 1\sim N 1∼N 中不与 N N N 含有共同因子的数的个数,也就是与 N N N 互质的个数。
根据欧拉函数的计算公式,就可以求解出欧拉函数。
【参考程序】
//求解n的欧拉函数
int phi(int n)
{
int ans=n;
for(int i=2;i<=sqrt(n);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;
}
时间复杂度 O ( N ) O(\sqrt N) O(N) 。
性质
性质 1 1 1: n > 1 n>1 n>1, 1 ∼ n 1\sim n 1∼n 中与 n n n 互质的数的和为 n × φ ( n ) 2 \frac {n\times \varphi(n)} 2 2n×φ(n) 。
性质 2 2 2: 若 a , b a,b a,b 互质,则 φ ( a b ) = φ ( a ) × φ ( b ) \varphi(ab)=\varphi(a)\times \varphi(b) φ(ab)=φ(a)×φ(b)。
证明:
因为 g c d ( n , x ) = g c d ( n , n − x ) gcd(n,x)=gcd(n,n-x) gcd(n,x)=gcd(n,n−x) (九章算术.更相减损术), n n n 和 x 、 n − x x、n-x x、n−x 不互质,因此与 n n n 不互质的数是成对出现的,和为 n n n ,平均值为 n 2 \frac n 2 2n,则与 n n n 互质的数的平均值为 n 2 \frac n 2 2n , 1 ∼ n 1\sim n 1∼n 中与 n n n 互质的数的和为 n × φ ( n ) 2 \frac {n\times \varphi(n)} 2 2n×φ(n) ,性质 1 1 1 成立。
根据欧拉函数的计算公式,对 a , b a,b a,b 分解质因数,直接可以得到性质 2 2 2 。
积性函数
如果 a , b a,b a,b 互质,有 f ( a , b ) = f ( a ) × f ( b ) f(a,b)=f(a)\times f(b) f(a,b)=f(a)×f(b),那么称函数 f f f 为积性函数。
性质
性质 3 3 3: 若 f f f 为积性函数,且在算术定理中, n = ∏ i = 1 m p i c i n=\prod_{i=1}^m p_i^{c_i} n=∏i=1mpici ,则 f ( n ) = ∏ i = 1 m f ( p i c i ) f(n)=\prod_{i=1}^m f(p_i^{c_i}) f(n)=∏i=1mf(pici)
性质 4 4 4: 设 p p p 是质数,若 p ∣ n p|n p∣n 且 p 2 ∣ n p^2|n p2∣n,则 φ ( n ) = φ ( n p ) × p \varphi(n)=\varphi(\frac n p)\times p φ(n)=φ(pn)×p
性质 5 5 5: 设 p p p 是质数,若 p ∣ n p|n p∣n 且 p 2 p^2 p2 不能整除 n n n ,则 φ ( n ) = φ ( n p ) × ( p − 1 ) \varphi(n)=\varphi(\frac n p)\times (p-1) φ(n)=φ(pn)×(p−1)
证明: 略,可参考《算法竞赛进阶指南》 0 x 32 0x32 0x32 约数。
例 1:「SDOI2008」仪仗队
【题目描述】
作为体育委员, C C C 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N ∗ N N * N N∗N的方阵,为了保证队伍在行进中整齐划一, C C C 君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在, C C C 君希望你告诉他队伍整齐时能看到的学生人数。
【输入】
共一个数 N N N 。
【输出】
共一个数,即 C C C 君应看到的学生人数。
【样例输入】
4
【样例输出】
9
【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 40000 1 ≤ N ≤ 40000 1≤N≤40000 。
【算法分析】
设左下角为 ( 0 , 0 ) (0,0) (0,0) ,右上角为 ( N − 1 , N − 1 ) (N-1,N-1) (N−1,N−1) 。
对于 ( x , y ) (x,y) (x,y) ,和 ( 0 , 0 ) (0,0) (0,0) 组成的线的斜率为 y x \frac y x xy ,若 x , y x,y x,y 存在最大公约数 p ( p > 1 ) p(p>1) p(p>1),那么 ( x p , y p ) (\frac x p,\frac y p) (px,py) 和 ( 0 , 0 ) (0,0) (0,0) 斜率也为 y x \frac y x xy, ( x p , y p ) (\frac x p,\frac y p) (px,py)和 ( x , y ) (x,y) (x,y)、 ( 0 , 0 ) (0,0) (0,0) 在同一条线上,且在 ( x , y ) (x,y) (x,y) 之前, ( 0 , 0 ) (0,0) (0,0) 就只能看到 ( x p , y p ) (\frac x p,\frac y p) (px,py)。
因此,除了 ( 1 , 0 ) , ( 0 , 1 ) , ( 1 , 1 ) (1,0),(0,1),(1,1) (1,0),(0,1),(1,1),$(x,y) $ 能被看到必须满足 g c d ( x , y ) = 1 , 1 ≤ x , y ≤ N − 1 , x ≠ y gcd(x,y)=1,1\le x,y\le N-1,x\neq y gcd(x,y)=1,1≤x,y≤N−1,x=y 。
同时,能看到的人数关于 ( 0 , 0 ) (0,0) (0,0) 和 ( N − 1 , N − 1 ) (N-1,N-1) (N−1,N−1) 的直线对称,因此可以只需要考虑一半即可,即 1 ≤ x < y ≤ N − 1 1\le x< y\le N-1 1≤x<y≤N−1 。对于任意 y ( 2 ≤ y ≤ N − 1 ) y\ (2\le y\le N-1) y (2≤y≤N−1) 有多少 x x x 满足 g c d ( x , y ) = 1 gcd(x,y)=1 gcd(x,y)=1,且 x < y x<y x<y 。这样的 x x x 个数就是 φ ( y ) \varphi(y) φ(y) 。
因此,最后的答案: a n s = 3 + 2 × ( φ ( 2 ) + φ ( 3 ) + . . . + φ ( N − 1 ) ) ans=3+2\times(\varphi(2)+\varphi(3)+...+\varphi(N-1)) ans=3+2×(φ(2)+φ(3)+...+φ(N−1)) 。
求 2 ∼ ( N − 1 ) 2\sim (N-1) 2∼(N−1) 的欧拉函数可以使用朴素做法,逐个求解,时间复杂度为 O ( N N ) O(N\sqrt N) O(NN) 。
利用埃氏筛法,按照欧拉函数的公式,在 O ( N log N ) O(N\log N) O(NlogN) 的时间求出,
int phi[100010];
void euler(int n)
{
for(int i=2;i<=n;i++) phi[i]=i;
for(int i=2;i<=n;i++)
{
if(phi[i]==i) //质数
{
for(int j=i;j<=n;j+=i) //i,i+i,i+2i...都包含i的质因子
phi[j]=phi[j]/i*(i-1);
}
}
}
线性筛法中,每个合数 n n n 只会被它最小的质因子 p p p 筛一次,可以利用性质 4 4 4 和性质 5 5 5 ,用 φ ( n p ) \varphi(\frac n p) φ(pn) 递推 φ ( n ) \varphi(n) φ(n) ,事件复杂度为 O ( N ) O(N) O(N) 。
方法一:朴素算法
#include <bits/stdc++.h>
using namespace std;
int phi(int n) //求解n的欧拉函数
{
int ans=n;
for(int i=2;i<=sqrt(n);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;
}
int main()
{
int n,ans=0;
cin>>n;
if(n==1) {cout<<0<<endl;return 0;}
for(int i=2;i<=n-1;i++)
ans+=phi(i);
cout<<3+2*ans<<endl;
return 0;
}
方法二:线性筛法
#include <bits/stdc++.h>
using namespace std;
const int N=40010;
int v[N],prime[N],phi[N];
void euler(int n)
{
memset(v,0,sizeof(v)); //保存最小质因子
int k=0; //质数个数
for(int i=2;i<=n;i++)
{
if(v[i]==0)
{
v[i]=i;
prime[++k]=i;
phi[i]=i-1; //质数i的欧拉函数为i-1
}
//给当前的数i乘以更小的质因子
for(int j=1;j<=k;j++)
{
if(prime[j]>v[i]||prime[j]>n/i) break;
v[i*prime[j]]=prime[j]; //更新i*prime[j]的最小质因子
phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]); //使用性质4和性质5
}
}
}
int main()
{
int n,ans=0;
cin>>n;
if(n==1) {cout<<0<<endl;return 0;}
euler(n);
for(int i=2;i<=n-1;i++)
ans+=phi[i];
cout<<3+2*ans<<endl;
return 0;
}