数论·约数

文章目录

  • [约数 / 因子](#约数 / 因子)
  • [试除法求约数: O ( n ) O(\sqrt{n}) O(n )](#试除法求约数: O ( n ) O(\sqrt{n}) O(n ))
  • 约数的数量与约数之和
    • 数学原理
    • [约数的数量: O ( log ⁡ n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n )](#约数的数量: O ( log ⁡ n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n ))
    • [约数之和: O ( log ⁡ n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n )](#约数之和: O ( log ⁡ n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n ))
  • [最大公约数: O ( log ⁡ max ⁡ ( a , b ) ) O(\log{\max{(a,b)}}) O(logmax(a,b))](#最大公约数: O ( log ⁡ max ⁡ ( a , b ) ) O(\log{\max{(a,b)}}) O(logmax(a,b)))

约数 / 因子

数学定义

  • 在数论中,约数等于因子
  • 例如对于12来说,约数有1,2,3,4,6,12。
  • 对于一个数x,任何能整除x的数都是x的约数。 a ∈ [ 1 , x ] , a ∣ x a\in [1,x], a|x a∈[1,x],a∣x

试除法求约数: O ( n ) O(\sqrt{n}) O(n )

869. 试除法求约数

数学原理

  • 约数的对称性:假设i是x的约数之一,那么x/i(注意可能与i相等)一定也是x的约数
  • 如果一个数 n n n 是合数,它一定有一个小于等于 n \sqrt{n} n 的因子。
  • 注意特判:i从1开始保证对于素数也成立

实现

cpp 复制代码
void get_divisors(int x) {
	set<int>res;
	for (int i = 1; i <= x / i; i++) {
		if (x % i == 0) {
			res.insert(i);
			res.insert(x / i);
		}
	}
	for (auto item : res) {
		cout << item << " ";
	}
	cout << endl;
}

约数的数量与约数之和

871. 约数之和
870. 约数个数

数学原理

算术基本定理(Fundamental Theorem of Arithmetic)指出:

每个大于 1 的正整数 n n n 都可以唯一地分解成有限个素数的乘积,即

n = p 1 a 1 p 2 a 2 ⋯ p k a k n = p_1^{a_1} p_2^{a_2} \cdots p_k^{a_k} n=p1a1p2a2⋯pkak

其中 p 1 < p 2 < ⋯ < p k p_1 < p_2 < \cdots < p_k p1<p2<⋯<pk 是互不相同的素数, a 1 , a 2 , ... , a k a_1, a_2, \dots, a_k a1,a2,...,ak 是正整数。若忽略素因数的排列顺序,该分解是唯一的。


约数的数量: O ( log ⁡ n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n )

  • 简单理解:我们有的是素因子,但是我们可以通过组合素因子的方法得到合数因子!
  • 注意:指数可以取0。

实现

  • 使用map存储一下素因子即可
cpp 复制代码
void solve() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int a;
		cin >> a;
		for (int j = 2; j <= a / j; j++) {
			while (a % j == 0) {
				mp[j]++;
				a /= j;
			}
		}
		if (a > 1)mp[a]++;
		//for (auto item : mp) {
		//	cout << item.first << " " << item.second << endl;
		//}
		//cout << endl;
	}
	ll res = 1;
	for (auto item : mp) {
		res *= (ll)(item.second + 1);
		res %= mod;
	}
	cout << res;
}

约数之和: O ( log ⁡ n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n )

  • 简单理解:既然我们知道任何一个因子都可以由素因子组合得到 。因此我们对所有因子进行求和,可以化简为对单个因子进行求和,最后乘积的形式

实现

  • 对单个因子求和的公式如下: S n = S n − 1 ∗ p + 1 S_n=S_{n-1}*p+1 Sn=Sn−1∗p+1,循环n次即可。
  • 最后分别乘在一起即可。
cpp 复制代码
int n;
unordered_map<int, int>mp;
void solve() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int a;
		cin >> a;
		for (int j = 2; j <= a / j; j++) {
			while (a % j == 0) {
				mp[j]++;
				a /= j;
			}
		}
		if (a > 1)mp[a]++;
	}
	//for (auto item : mp) {
	//	cout << item.first << " " << item.second << endl;
	//}
	//cout << endl;
	ll res = 1;
	for (auto item : mp) {
		ll sum = 1;//S0
		int p = item.first;
		for (int i = 1; i <= item.second; i++) {
			sum = (ll)(sum * p) + 1;
			sum %= mod;
		}
		//cout << sum << endl;
		res = (res * sum) % mod;
	}
	cout << res;

}

最大公约数: O ( log ⁡ max ⁡ ( a , b ) ) O(\log{\max{(a,b)}}) O(logmax(a,b))

872. 最大公约数

数学原理

  • g c d ( a , b ) = g c d ( b , r ) gcd(a,b)=gcd(b,r) gcd(a,b)=gcd(b,r),where a = b q + r a=bq+r a=bq+r
  • 证明思路:a,b,r的公约数都是d。
  • 假设d是a和b的公约数,那么证明d也是r和b的公约数;假设d是b和r的公约数,那么d也是a的公约数。使用整除的线性性质即可d|a,d|b -> d|ax+by

实现

  • 注意gcd(a,0)定义为a。a一定要大于b!a一定要大于b!a一定要大于b!
cpp 复制代码
int gcd(int x, int y) {// x>y
	if (y == 0)return x;
	else {
		return gcd(y, x % y);
	}
}
相关推荐
会编程的土豆2 小时前
【数据结构与算法】最短路径---Dijkstra 算法
数据结构·c++·算法
2401_879693872 小时前
C++中的观察者模式实战
开发语言·c++·算法
炽烈小老头2 小时前
【 每天学习一点算法 2026/03/24】寻找峰值
学习·算法
fff9811182 小时前
C++与Qt图形开发
开发语言·c++·算法
计算机安禾2 小时前
【数据结构与算法】第3篇:C语言核心机制回顾(二):动态内存管理与typedef
c语言·开发语言·数据结构·c++·算法·链表·visual studio
njidf3 小时前
C++中的访问者模式
开发语言·c++·算法
C_Si沉思3 小时前
C++中的工厂模式变体
开发语言·c++·算法
C羊驼3 小时前
C语言学习笔记(十五):预处理
c语言·经验分享·笔记·学习·算法
m0_569881473 小时前
C++中的适配器模式变体
开发语言·c++·算法