互质与欧拉函数
互质
任意自然数 a,ba,ba,b,若 gcd(a,b)=1gcd(a,b)=1gcd(a,b)=1,则称 a,ba,ba,b 互质。
对于三个数或更多个数,将 gcd(a,b,c)=1gcd(a,b,c)=1gcd(a,b,c)=1 的情况称为 a,b,ca,b,ca,b,c 互质。把 gcd(a,b)=gcd(b,c)=gcd(a,c)=1gcd(a,b)=gcd(b,c)=gcd(a,c)=1gcd(a,b)=gcd(b,c)=gcd(a,c)=1 称为两两互质,两者有明显的区别,显然,后者要求更高。
欧拉函数
1∼N1\sim N1∼N 中与 NNN 互质的个数被称为欧拉函数,记为 φ(N)\varphi(N)φ(N) 。
在算术基本定理中,N=p1c1×p2c2×...×pmcmN=p_1^{c_1}\times p_2^{c_2}\times ...\times p_m^{c_m}N=p1c1×p2c2×...×pmcm,p1,p2...pmp_1,p_2...p_mp1,p2...pm 为质数,则:
φ(N)=N×p1−1p1×p2−1p2×...×pm−1pm\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
证明:
若 ppp 是 NNN 的质因子,则 1∼N1\sim N1∼N 中 ppp 的倍数有:p,2p,3p...(Np)×pp,2p,3p...(\frac N p)\times pp,2p,3p...(pN)×p,共 Np\frac N ppN (整除)个。同理,若 qqq 也是 NNN 的质因子,则 1∼N1\sim N1∼N 中 qqq 的倍数有:q,2q,3q...(Nq)×qq,2q,3q...(\frac N q)\times qq,2q,3q...(qN)×q,共 Nq\frac N qqN (整除)个。同时 p×qp\times qp×q 的倍数即被 ppp 排除了,又被 qqq 排除了,所有需要加回来。因此,1∼N1\sim N1∼N 中不与 NNN 含有共同质因子 ppp 和 qqq 的个数为:
N−Nq−Np+Npq=N×(1−1p−1q+1pq)=N×(1−1p)×(1−1q)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∼N1\sim N1∼N 中不与 NNN 含有共同因子的数的个数,也就是与 NNN 互质的个数。
根据欧拉函数的计算公式,就可以求解出欧拉函数。
【参考程序】
//求解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) 。
性质
性质 111:n>1n>1n>1,1∼n1\sim n1∼n 中与 nnn 互质的数的和为 n×φ(n)2\frac {n\times \varphi(n)} 22n×φ(n) 。
性质 222: 若 a,ba,ba,b 互质,则 φ(ab)=φ(a)×φ(b)\varphi(ab)=\varphi(a)\times \varphi(b)φ(ab)=φ(a)×φ(b)。
证明:
因为 gcd(n,x)=gcd(n,n−x)gcd(n,x)=gcd(n,n-x)gcd(n,x)=gcd(n,n−x) (九章算术.更相减损术),nnn 和 x、n−xx、n-xx、n−x 不互质,因此与 nnn 不互质的数是成对出现的,和为 nnn ,平均值为 n2\frac n 22n,则与 nnn 互质的数的平均值为 n2\frac n 22n ,1∼n1\sim n1∼n 中与 nnn 互质的数的和为 n×φ(n)2\frac {n\times \varphi(n)} 22n×φ(n) ,性质 111 成立。
根据欧拉函数的计算公式,对 a,ba,ba,b 分解质因数,直接可以得到性质 222 。
积性函数
如果 a,ba,ba,b 互质,有 f(a,b)=f(a)×f(b)f(a,b)=f(a)\times f(b)f(a,b)=f(a)×f(b),那么称函数 fff 为积性函数。
性质
性质 333: 若 fff 为积性函数,且在算术定理中,n=∏i=1mpicin=\prod_{i=1}^m p_i^{c_i}n=∏i=1mpici ,则 f(n)=∏i=1mf(pici)f(n)=\prod_{i=1}^m f(p_i^{c_i})f(n)=∏i=1mf(pici)
性质 444: 设 ppp 是质数,若 p∣np|np∣n 且 p2∣np^2|np2∣n,则 φ(n)=φ(np)×p\varphi(n)=\varphi(\frac n p)\times pφ(n)=φ(pn)×p
性质 555: 设 ppp 是质数,若 p∣np|np∣n 且 p2p^2p2 不能整除 nnn ,则 φ(n)=φ(np)×(p−1)\varphi(n)=\varphi(\frac n p)\times (p-1)φ(n)=φ(pn)×(p−1)
证明: 略,可参考《算法竞赛进阶指南》0x320x320x32 约数。
例 1:「SDOI2008」仪仗队
【题目描述】
作为体育委员, CCC 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N∗NN * NN∗N的方阵,为了保证队伍在行进中整齐划一, CCC 君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在, CCC 君希望你告诉他队伍整齐时能看到的学生人数。
【输入】
共一个数 NNN 。
【输出】
共一个数,即 CCC 君应看到的学生人数。
【样例输入】
4
【样例输出】
9
【数据范围】
对于 100%100\%100% 的数据,1≤N≤400001 ≤ N ≤ 400001≤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) 组成的线的斜率为 yx\frac y xxy ,若 x,yx,yx,y 存在最大公约数 p(p>1)p(p>1)p(p>1),那么(xp,yp)(\frac x p,\frac y p)(px,py) 和 (0,0)(0,0)(0,0) 斜率也为 yx\frac y xxy,(xp,yp)(\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) 就只能看到 (xp,yp)(\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) $ 能被看到必须满足 gcd(x,y)=1,1≤x,y≤N−1,x≠ygcd(x,y)=1,1\le x,y\le N-1,x\neq ygcd(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−11\le x< y\le N-11≤x<y≤N−1 。对于任意 y (2≤y≤N−1)y\ (2\le y\le N-1)y (2≤y≤N−1) 有多少 xxx 满足 gcd(x,y)=1gcd(x,y)=1gcd(x,y)=1,且 x<yx<yx<y 。这样的 xxx 个数就是 φ(y)\varphi(y)φ(y) 。
因此,最后的答案:ans=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(NN)O(N\sqrt N)O(NN) 。
利用埃氏筛法,按照欧拉函数的公式,在 O(NlogN)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);
}
}
}
线性筛法中,每个合数 nnn 只会被它最小的质因子 ppp 筛一次,可以利用性质 444 和性质 555 ,用 φ(np)\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;
}