约数定义
若整数 n 除以整数 d 的余数为 0,即 d 能整除 n,则称 d 是 n 的约数,n 是 d 的倍数,记为 d|n。
算术基本定理的推论
在算术基本定理中,若正整数 N 被唯一分解为 N = ,其中 ci 都是正整数,pi 都是质数,且满足 p1<p2<...<pm,则 N 的正约数集合可写作:
{},其中 0 ≤ bi ≤ ci
N 的正约数个数为(Π表示连乘积符号,与∑类似):
(c1 + 1) * (c2 + 1) *...* (cm + 1) =
N 的所有正约数的和为:
求 N 的正约数集合——试除法
若 d ≥ 是 N 的约数,则 N/d ≤
也是 N 的约数。换言之,约数总是成对出现的(除了对于完全平方数,
会单独出现)
因此,只需要扫描 d = 1~,尝试 d 能否整除 N,若能整除,则 N/d 也是 N 的约数。时间复杂度为 O(
)
int factor[1600];
int m=0;
for(int i=1;i*i<=n;i++){
if(n%i==0){
factor[++m]=i;
if(i!=n/i) factor[++m]=n/i;
}
}
for(int i=1;i<=m;i++) cout<<factor[i]<<endl;
试除法的推论
一个整数 N 的约数个数上界为
求 1~N 每个数的正约数集合——倍数法
若用“”试除法分别求出 1~N 每个数的正约数集合,时间复杂度过高,为O()。可以反过来考虑,对于每个数 d,1~N 中以 d 为约数的数就是 d 的倍数 d,2d,3d,...,(N/d)*d。以下程序采用“倍数法”求出 1~N 每个数的正约数集合:
vector<int> factor[500010];
for(int i=1;i<=n;i++)
for(int j=1;j<=n/i;j++)
factor[i*j].push_back(i);
for(int i=1;i<=n;i++){
for(int j=0;j<factor[i].size();j++)
printf("%d",factor[i][j]);
puts("");
}
上述算法的时间复杂度为 O(NlogN)
倍数法的推论
1~N 每个数的约数个数的总和大约为 NlogN
最大公约数
定义
若自然数 d 同时是自然数 a 和 b 的约数,则称 d 是 a 和 b 的公约数。在所有 a 和 b 的公约数中最大的一个,成为 a 和 b 的最大公约数,记为 gcd(a,b)。
若自然数 m 同时是自然数 a 和 b 的倍数,则称 m 是 a 和 b的最小公倍数,记为 lcm(a,b)。
同理,我们也可以定义三个数以及更多个数的最大公约数/最小公倍数。
定理
任意a,b∈N gcd(a,b)*lcm(a,b) = a*b
九章算术 · 更相减损术
任意a,b∈N,a≥b,有gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)
欧几里得算法
任意a,b∈N,b≠0 gcd(a,b)=gcd(b,a mod b)
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
使用欧几里得算法求最大公约数的复杂度为 O(log(a+b))。欧几里得算法是最常用的求最大公约数的方法。不过,因为高精度除法(取模)不容易实现,需要做高精度运算时,可考虑用更相减损数代替欧几里得算法。
互质与欧拉函数
定义
任意a,b∈N,若gcd(a,b)=1,则称 a,b 互质
对于三个数或更多个数的情况,我们把 gcd(a,b,c)=1 的情况称为 a,b,c 互质。把 gcd(a,b)=gcd(a,b)=gcd(b,c)=1 称为 a,b,c 两两互质。
欧拉函数
1~N 中与 N 互质的数的个数被称为欧拉函数,记为
= N * (p1 - 1)/p1 * (p2 - 1)/p2 * (p3 - 1)/p3 * ... * (pm - 1)/pm = 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;
}
性质:
1. 任意n>1,1~n 中与 n 互质的数的和为 n*/2
2. 若 a,b 互质,则
积性函数:如果当 a,b 互质时,有 f(ab)=f(a)*f(b),那么称函数 f 为积性函数
3. 若 f 是积性函数,且在算术基本定理中 ,则
4. 设 p 为质数,若 p|n 且 p^2|n,则
5. 设 p 为质数,若 p|n 且 p^2!|n,则
6.