算法学习笔记(34)——约数
约数
约数的定义
若整数 除以整数 的余数为 ,即 能整除 ,则称 是 的约数, 是 的倍数,记为 。
算数基本定理的推论
正约数集合
在算数基本定理中,若正整数 被唯一分解为 ,其中 都是正整数, 都是质数,且满足 ,则 的正约数集合可以写作:
正约数个数
此处 代表质数 的 次方。
正约数之和
上式按照乘法多项式展开之后的每一项都是 的一个约数。
一、试除法求约数
如果 是 的约数,那么 也是 的约数。换言之,约数总是成对出现的(对于完全平方的数字, 会单独出现一次)。
因此,只需扫描 到 之间的数字,尝试能否整除 ,若能整除,则 也是 的约数。
时间复杂度:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void get_divisors(int n)
{
// 用于存储约数
vector<int> res;
// 枚举从 1 到 sqrt(n) 的数
for (int i = 1; i <= n / i; i ++ )
// 如果 i 是 n 的约数
if (n % i == 0) {
// 将 i 存起来
res.push_back(i);
// 如果不是完全平方数,则将 n/i 也存起来
if (i != n / i) res.push_back(n / i);
}
// 排序约数数组
sort(res.begin(), res.end());
for (auto i : res) cout << i << ' ';
puts("");
}
int main()
{
int n;
cin >> n;
while (n -- ) {
int a;
cin >> a;
get_divisors(a);
}
return 0;
}
二、约数个数
利用算数基本定理的推论
时间复杂度:
#include <iostream>
#include <unordered_map>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
int main()
{
int n;
cin >> n;
// 采用哈希表存储每一个质因子对应出现的次数
unordered_map<int, int> primes;
while (n -- ) {
int a;
cin >> a;
// 筛质数
for (int i = 2; i <= a / i; i ++ )
while (a % i == 0) {
a /= i;
primes[i] ++;
}
if (a > 1) primes[a] ++;
}
LL res = 1;
// 代公式
for (auto prime : primes) res = res * (prime.second + 1) % MOD;
cout << res << endl;
return 0;
}
三、约数之和
时间复杂度:
#include <iostream>
#include <unordered_map>
using namespace std;
const int MOD = 1e9 + 7;
typedef long long LL;
int main()
{
int n;
cin >> n;
unordered_map<int, int> primes;
while (n -- ) {
int a;
cin >> a;
for (int i = 2; i <= a / i; i ++ )
while (a % i == 0) {
a /= i;
primes[i] ++;
}
if (a > 1) primes[a] ++;
}
LL res = 1;
for (auto prime : primes) {
int p = prime.first, c = prime.second;
LL t = 1;
while (c -- ) t = (t * p + 1) % MOD;
res = res * t % MOD;
}
cout << res << endl;
return 0;
}
四、最大公约数
欧几里得算法
证明:
- 若 ,则 ,显然成立。
- 若 ,不妨设 ,其中 。显然 。对于 的任意公约数 ,因为 , ,故 ,即 ,因此 也是 的公约数。反之亦成立。故 的公约数集合与 的公约数集合相同。于是他们的最大公约数自然相等。
时间复杂度:
#include <iostream>
using namespace std;
int gcd(int a, int b)
{
// 0可以被任何数整除
return b ? gcd(b, a % b) : a;
}
int main()
{
int n;
cin >> n;
while (n -- ) {
int a, b;
cin >> a >> b;
cout << gcd(a, b) << endl;
}
return 0;
}
也可调用STL的__gcd()
函数:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin >> n;
while (n -- ) {
int a, b;
cin >> a >> b;
cout << __gcd(a, b) << endl;
}
return 0;
}
欧几里得算法是最常用的求最大公约数的算法。不过,因为高精度除法(取模)不容易实现,需要做高精度运算时,可考虑用更相减损数代替欧几里得算法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】