约数
约数
PS:以下讨论的任意都在正整数范围内。
若对于数字 与 ,如果 ,使 。则称 是 的约数,记为 。 是 的倍数。
否则 不是 的约数,记为 。
求 的正约数集合——试除法
枚举 的所有数字 ,判断 是否能够被 整除,若能则 与 都是 的约数。
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;
}
推论:
-
除完全平方数的 以外,所有约数成对出现。
-
的约数个数小于 。
求 中每个数的正约数集合——倍数法。
朴素扫描 所有数并暴力 找约数,时间复杂度高达 。
考虑对于 ,找 在 以内的倍数。
时间复杂度 。
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 ;
}
推论:
- 中所有数的约数个数和约为 。
算数基本定理(唯一分解定理)
.
通俗来讲,就是任何一个不等于 的正整数都可以拆成若干个质数的乘积的形式。
证明:反证法。假设存在一些大于 的数不可拆分成若干质数乘积的形式。
设其中最小的一个数是 。
由定义知, 不是质数就是合数。
若 为质数,拆分 显然存在。
若 为合数,则被拆成 的形式,由于 最小,所以 满足条件,所以 满足条件,与假设矛盾。故假设不成立,原命题成立。
证毕。
分解质因数——试除法
引理:对于一个数 ,仅可能存在一个质因数大于 。
证明:假设存在两个大于 的质因数 (可能相等)。
由于分解的质因数相乘等于原数,所以 应小于等于 ,但是显然, 大于 。
与命题矛盾,故假设不成立,原命题成立。
证毕。
所以只需扫描 的所有质数并分解至无法再分,最后判唯一大于 的质数即可。
时间复杂度 。
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));
}
性质:
若 ,则:
- 的正约数个数为:.
证明:依次考虑所有质因子。
第 个质因子可以选 个、选 个、选 个 选 个。
有 种选择。
因为考虑每个质因子是分步进行,故分步乘法原理得证。
证毕。
- 的正约数之和为 。
最大公约数与最小公倍数
对于数字 ,。若存在数字 。使 且 。则称 为 与 的公约数。
其中最大的 称为 与 的最大公约数。写作 。
对于数字 ,。若存在数字 。使 且 。则称 为 与 的公倍数。
其中最小的 称为 与 的最小公倍数。写作 。
若 ,则称 与 互质。
对于更多数的情况, 称为 互质,称 为 两两互质。
规定:, 不存在。
性质
-
对于任意 ,有 。
-
。
证明:反证法。设 ,。
那么上式等价于 。
假设 ,那么设 。
那么 。
由于 有公因子 ,与 最大矛盾。
故假设不成立,原命题成立。
证毕。
- 若 且 ,则有 。
简证:若 ,则 ,与条件矛盾。
证毕。
- 对于任意 且 ,有 。
证明:设 ,那么 与 的最大公因子是 。
显然, 是整数。
证毕。
- 对于任意 且 ,有 。
证明:设 。
显然有 ,.
因为 互质,故 .
故 。
证毕。
- 。
简证:将 同时乘 ,其公因子又多了 。显然最大。
证毕。
重要性质
- 。
:数学归纳法,当 时,原式等价于 显然成立。
设命题在 时成立,当 时:
设
则上式等价于:
最后一步成立是因为 一定包含的是 没有的质因子,所以可以直接乘(玄学)。
证毕。
求解最大公约数的方法
更相减损术: 若 ,。
欧几里得算法 。( 表示 的余数。)
证明:若 ,命题显然成立。
若 ,设 ,即 。
设 为 的任意一个公约数。
由于 ,所以 ,即 。
所以 的公约数集合与 的公约数集合相同,其最大值自然相同。
证毕。
int gcd(int a,int b) {
return b?gcd(b,a%b):a;
}
时间复杂度约 。
欧拉函数
定义函数 表示 中与 互质的数的个数。
就是大名鼎鼎的欧拉函数。
求法: 若将 分解质因数为 。
则有:
证明:设 存在质因子 ,则 中 的倍数有 共 个。
在设 存在另一种质因子 ,则 中 的倍数有 共 个。
由于会去掉两次 的倍数,所以还要加上 。
故数量为 。(容斥原理)
对 的全部质因子使用容斥原理,命题得证。
所以只需对 分解质因数,即可顺便求欧拉函数。
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;
}
性质:
- 中与 互质的数的和为 。
证明:设 中与 互质的数构成的数列为 。
显然,。
类比等差数列求和,可得对应相加之和为 ,除以 则命题得证。
证毕。
- 若 ,则 。
简证:由于 与 互质,故 与 的质因子类别交集为空。
故得证。
其实,若函数 满足 :
- 若 互质,则称函数 为积性函数。
- 若 不一定互质,则称函数 为完全积性函数。
- 若 分解质因数后为 ,。
简证:不同质因子的若干次幂之间显然互质,根据性质 得证。
事实上,该性质对所有积性函数都成立。
- 对于一个数 :
- 若 则 。
- 若 则 。
证明:设 分解质因数后为 。
对于第一种情况, 必然是 的其中一个。
故 。
对于第二种情况:
。
证毕。
证明:令 。
设 与 互质。。
.
所以 是积性函数,满足性质 。
故 。
由于
即 。
故 .
即 .
证毕。
欧拉函数递推
求 之间所有数的欧拉函数。
当然可以 直接暴力一个个求, 直接炸。
根据性质 ,可以根据质数 从 递推到 。
所以可以通过 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;
}
}
时间复杂度 。
欧拉:
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);
}
}
}
时间复杂度 。
整除分块
对于以下的式子:
这个式子直接求是 的。
性质:
- 加数最多出现 种,且同种加数连续。
简证:显然,加数只会是 的约数,而 的约数小于 。
由于加数的分母单调递增,分子不变,故加数单调不增。
证毕。
考虑枚举每一种加数,求出该种加数对应的区间,答案加上区间长度乘此加数即可。
设当前区间左端点为 ,则此区间对应的值为 。
如果能求出右端点 ,就可以求出该区间对应的贡献,还可以顺便求出下一个区间的左端点 。
所以现在的问题就是如何求 。
设 为当前区间的值。
则应满足 。
所以 。
又因为要取最大的 并且 为整数。
故 。
时间复杂度:由于区间数量最多 个,所以时间复杂度为 。
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';
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具