约数

约数

PS:以下讨论的任意都在正整数范围内。

若对于数字 dn,如果 kZ,使 k×d=n。则称 dn 的约数,记为 d|nnd 的倍数。

否则 d 不是 n 的约数,记为 dn


n 的正约数集合——试除法

枚举 1n 的所有数字 x,判断 n 是否能够被 x 整除,若能则 xn÷x 都是 n 的约数。

vector<int>Apx(int n) {
	int cnt=sqrt(n);
	vector<int>res;res.clear();
	for(int i=1;i<=cnt;++i) {
		if(n%i) continue;
		res.push_back(i);
		if(i*i==n) continue;
		res.push_back(n/i);
	}
	return res;
}

推论:

  • 除完全平方数的 n 以外,所有约数成对出现。

  • n 的约数个数小于 2×n


1n 中每个数的正约数集合——倍数法。

朴素扫描 1n 所有数并暴力 n 找约数,时间复杂度高达 O(nn)

考虑对于 1in,找 in 以内的倍数。

时间复杂度 O(nlogn)

vector<int>Ap[N];
void Init() {
	for(int i=1;i<=n;++i) 
		for(int j=i;j<=n;j+=i) Ap[j].push_back(i);
	return ; 
}

推论:

  • 1n 中所有数的约数个数和约为 nlogn

算数基本定理(唯一分解定理)

xN+,x1,{pm},{cm},piP,x=i=1mpici.

通俗来讲,就是任何一个不等于 1 的正整数都可以拆成若干个质数的乘积的形式。

证明:反证法。假设存在一些大于 1 的数不可拆分成若干质数乘积的形式。

设其中最小的一个数是 k

由定义知,k 不是质数就是合数。

k 为质数,拆分 k=k 显然存在。

k 为合数,则被拆成 a×b 的形式,由于 k 最小,所以 a,b 满足条件,所以 k 满足条件,与假设矛盾。故假设不成立,原命题成立。

证毕。

分解质因数——试除法

引理:对于一个数 x,仅可能存在一个质因数大于 x

证明:假设存在两个大于 x 的质因数 p,q(可能相等)。

由于分解的质因数相乘等于原数,所以 p×q 应小于等于 x,但是显然,p×q 大于 x

与命题矛盾,故假设不成立,原命题成立。

证毕。

所以只需扫描 1n 的所有质数并分解至无法再分,最后判唯一大于 n 的质数即可。

时间复杂度 O(n)

vector<pair<int,int> >Pa;
void Prime(int x) {
	int cnt=sqrt(x);
	FOR(i,2,cnt) {
		if(x%i) continue;
		int cnt=0;
		while(x%i==0) {
			cnt++;
			x/=i;
		}
		Pa.push_back(mkp(i,cnt));
	}
	if(x>1) Pa.push_back(mkp(x,1));
}

性质:

x=i=1mpici,则:

  • x 的正约数个数为:i=1m(ci+1).

证明:依次考虑所有质因子。

i 个质因子可以选 0 个、选 1 个、选 2ci 个。

ci+1 种选择。

因为考虑每个质因子是分步进行,故分步乘法原理得证。

证毕。

  • x 的正约数之和为 k=1m(i=0ckpki)

最大公约数与最小公倍数

对于数字 xy。若存在数字 d。使 dxdy。则称 dxy公约数

其中最大的 d 称为 xy最大公约数。写作 gcd(a,b)

对于数字 xy。若存在数字 d。使 xdyd。则称 dxy公倍数

其中最小的 d 称为 xy最小公倍数。写作 lcm(a,b)

gcd(x,y)=1,则称 xy 互质

对于更多数的情况,gcd(x,y,z)=1 称为 x,y,z 互质,称 gcd(x,y)=gcd(y,z)=gcd(x,z)=1x,y,z 两两互质。

规定:gcd(a,0)=agcd(0,0) 不存在。

性质

  • 对于任意 x,y,有 lcm(x,y)=x×ygcd(x,y)

  • gcd(xgcd(x,y),ygcd(x,y))=1

证明:反证法。设 x=gcd(x,y)×k1y=gcd(x,y)×k2

那么上式等价于 gcd(k1,k2)=1

假设 gcd(k1,k2)=d(d>1),那么设 z1=k1d,z2=k2d

那么 x=(gcd(x,y)×d)×z1,y=(gcd(x,y)×d)×z2

由于 x,y 有公因子 gcd(x,y)×d,与 gcd(x,y) 最大矛盾。

故假设不成立,原命题成立。

证毕。

  • k2(k1×d)gcd(k1,k2)=1,则有 k2d

简证:若 k2d,则 k2d×k1,与条件矛盾。

证毕。

  • 对于任意 dxdy,有 dgcd(x,y)

证明:设 d2=gcd(x÷d,y÷d),那么 xy 的最大公因子是 d×d2=gcd(x,y)

显然,d2 是整数。

证毕。

  • 对于任意 xdyd,有 lcm(x,y)d

证明:设 x=k1×gcd(x,y),y=k2×gcd(x,y)

显然有 k1dgcd(x,y),k2dgcd(x,y).

因为 k1,k2 互质,故 (k1×k2)dgcd(x,y).

k1×k2×gcd(x,y)dlcm(a,b)d

证毕。

  • gcd(a×n,b×n)=n×gcd(a,b)

简证:将 a,b 同时乘 n,其公因子又多了 n×gcd(a,b)。显然最大。

证毕。

重要性质

  • gcd(a,lcmi=1nbi)=lcmi=1ngcd(a,bi)

Proof:数学归纳法,当 n=1 时,原式等价于 gcd(a,b1)=gcd(a,b1) 显然成立。

设命题在 n=k 时成立,当 n=k+1 时:

gcd(a,lcmi=1k+1bi)=gcd(a,(lcmi=1kbi)×bk+1gcd(lcmi=1kbi,bk+1))

z=bk+1gcd(lcmi=1kbi,bk+1)

则上式等价于:

gcd(a,lcmi=1k+1bi)=gcd(a,(lcmi=1kbi)×z)=gcd(a,lcmi=1kbi)×gcd(a,z)=(lcmi=1kgcd(a,bi))×gcd(a,z)=lcmi=1k+1gcd(a,bi)

最后一步成立是因为 gcd(a,z) 一定包含的是 lcmi=1kbi 没有的质因子,所以可以直接乘(玄学)。

证毕。


求解最大公约数的方法

更相减损术: 若 a>bgcd(a,b)=gcd(a,ab)=gcd(b,ab)

欧几里得算法 gcd(a,b)=gcd(b,amodb)。(amodb 表示 a÷b 的余数。)

证明:若 a<b,命题显然成立。

ab,设 a=q×b+r,即 r=amodb

da,b 的任意一个公约数。

由于 da,d(b×q),所以 d(aq×b),即 dr

所以 a,b 的公约数集合与 b,amodb 的公约数集合相同,其最大值自然相同。

证毕。

int gcd(int a,int b) {
	return b?gcd(b,a%b):a;
}

时间复杂度约 O(log(a+b))

欧拉函数

定义函数 φ(n) 表示 1n 中与 n 互质的数的个数。

φ(n) 就是大名鼎鼎的欧拉函数

求法: 若将 n 分解质因数为 n=i=1mpici

则有:

φ(n)=n×pP,pn(11p)

证明:设 n 存在质因子 p,则 1np 的倍数有 p,2×p,3×p,,(n÷p)×pn÷p 个。

在设 n 存在另一种质因子 q,则 1nq 的倍数有 q,2×q,3×q,,(n÷q)×qn÷q 个。

由于会去掉两次 p×q 的倍数,所以还要加上 n÷(p×q)

故数量为 nnpnq+np×q=n(11p)(11q)。(容斥原理)

n 的全部质因子使用容斥原理,命题得证。

所以只需对 n 分解质因数,即可顺便求欧拉函数。

int phi(int x) {
	int cnt=sqrt(x),res=x;
	FOR(i,2,cnt) {
		if(x%i) continue;
		while(x%i==0) x/=i;
		res/=i;res*=(i-1);
	}
	if(x>1) res/=x,res*=(x-1);
	return res;
}

性质:

  • 1n 中与 n 互质的数的和为 n×φ(n)2

证明:设 1n 中与 n 互质的数构成的数列为 p1,p2,p3,,pφ(n)

显然,p1=1,pφ(n)=n1

类比等差数列求和,可得对应相加之和为 n×φ(n),除以 2 则命题得证。

证毕。

  • gcd(a,b)=1,则 φ(ab)=φ(a)×φ(b)

简证:由于 ab 互质,故 ab 的质因子类别交集为空。

故得证。

其实,若函数 f 满足 f(ab)=f(a)×f(b)

- 若 a,b 互质,则称函数 f积性函数

- 若 a,b 不一定互质,则称函数 f完全积性函数

  • n 分解质因数后为 i=1mpiciφ(n)=i=1mφ(pici)

简证:不同质因子的若干次幂之间显然互质,根据性质 2 得证。

事实上,该性质对所有积性函数都成立。

  • 对于一个数 pP

- 若 dnφ(n×p)=φ(n)×p

- 若 dnφ(n×p)=φ(n)×(p1)

证明:设 n 分解质因数后为 i=1mpici

对于第一种情况,p 必然是 pi 的其中一个。

φ(n×p)=n×p×i=1m(11pi)=φ(n)×p

对于第二种情况:

φ(n×p)=n×p×i=1m(11pi)×(11p)=φ(n)×p×(11p)=φ(n)×p1

证毕。

  • dnφ(d)=n

证明:令 f(n)=dnφ(d)

mn 互质。f(m)=dnφ(d)

f(nm)=dnmφ(d)=(dnφ(d))(dmφ(d))=f(n)×f(m).

所以 f 是积性函数,满足性质 3

f(n)=i=1mf(pici)

由于 f(pici)=j=0ciφ(pij)=1+j=1cipij1×(pi1)=1+(pi1)×(pici1)pi1=1+pici1=pici

f(pici)=pici

f(n)=i=1mf(pici)=i=1mpici=n.

dnφ(d)=n.

证毕。


欧拉函数递推

Q:1n 之间所有数的欧拉函数。

当然可以 O(nn) 直接暴力一个个求,n1×106 直接炸。

根据性质 4,5,可以根据质数 pφ(n) 递推到 φ(n×p)

所以可以通过 Eratosthenes 筛法或欧拉筛法来线性地递推欧拉函数。

Eratosthenes:

bool vis[N];
int phi[N];
void Eratosthenes() {
	FOR(i,1,n) phi[i]=i;
	FOR(i,2,n) {
		if(vis[i]) continue;
		for(int j=i;j<=n;j+=i) 
			phi[j]/=i,phi[j]*=(i-1),vis[j]=1;
	}
}

时间复杂度 O(nloglogn)

欧拉:

int v[N],phi[N];
vector<int>prime;
void Euler() {
	FOR(i,1,n) phi[i]=i;
	FOR(i,2,n) {
		if(!v[i]) v[i]=i,phi[i]=i-1,prime.push_back(i);
		for(int p:prime) {
			if(p*i>n||v[i]<p) break;
			v[i*p]=p;
			phi[p*i]=phi[i]*(i%p?p-1:p);
		}
	}
} 

时间复杂度 O(n)

整除分块

对于以下的式子:

i=1nni

这个式子直接求是 O(n) 的。

性质:

  • 加数最多出现 2×n 种,且同种加数连续。

简证:显然,加数只会是 n 的约数,而 n 的约数小于 2n

由于加数的分母单调递增,分子不变,故加数单调不增。

证毕。

考虑枚举每一种加数,求出该种加数对应的区间,答案加上区间长度乘此加数即可。

设当前区间左端点为 l,则此区间对应的值为 nl

如果能求出右端点 r,就可以求出该区间对应的贡献,还可以顺便求出下一个区间的左端点 l=r+1

所以现在的问题就是如何求 r

k 为当前区间的值。

则应满足 r×kn

所以 rnk

又因为要取最大的 r 并且 r 为整数。

r=nk=nnl

时间复杂度:由于区间数量最多 2×n 个,所以时间复杂度为 O(n)

int ans=0;
for(int l=1,r;l<=n;l=r+1) {
	r=(n/(n/l));
	ans+=(r-l+1)*(n/l);
}
cout<<ans<<'\n';
posted @   cannotmath  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示