约数

约数

什么是约数

约数,又称之为因数。整数 a a a除以整数 b ( b ! = 0 ) b(b!=0) b(b!=0)除得的商正好是整数而没有余数。我们就说 a a a能被 b b b整除,或 b b b能整除 a a a a a a称为 b b b的倍数, b b b称为 a a a的约数。

约数的相关运算

求一个数的所有约数

用试除法枚举,时间复杂度 O ( n ) O(\sqrt n) O(n )

void Divisor(int n){
	int t;
	for(int i = 1; i <= sqrt(n); i++){
		if(n % i == 0) cout << i << " ";
	}
	int res = sqrt(n);
	if(res * res == n)  t = res - 1;
	else t = res;
	for(int i = t; i >= 1; i--){
		if(n % i == 0) cout << n/i << " ";
	}
} 
如何求约数个数

我们都知道,每一个合数都可以写成几个素数相乘的形式,其中每个素数都是这个合数的因数。所以我们就可以把 n n n分解成: n = p 1 a 1 × p 2 a 2 × ⋯ × p k a k n=p_1^{a_1}\times p_2^{a_2}\times \dots \times p_k^{a_k} n=p1a1×p2a2××pkak,其中 p 1 , p 2 , … , p k p_1,p_2,\dots,p_k p1,p2,,pk是不同的素数, a 1 , a 2 , … , a k a_1,a_2,\dots,a_k a1,a2,,ak是正整数。

由约数定义可知 p 1 a 1 p_1^{a_1} p1a1的约数有: p 1 0 , p 1 1 , p 1 2 , . . . . p 1 a 1 p_1^0, p_1^1, p_1^2,....p_1^{a_1} p10,p11,p12,....p1a1,共 ( a 1 + 1 ) (a_1+1) (a1+1)个;同理 p 2 a 2 p_2^{a_2} p2a2的约数有 ( a 2 + 1 ) (a_2+1) (a2+1)个, … \dots p k a k p_k^{a_k} pkak的约数有 ( a k + 1 ) (a_k+1) (ak+1)个。

故根据乘法原理: n n n的正约数的个数为 ∏ i = 0 n ( a i + 1 ) = ( a 1 + 1 ) × ( a 2 + 1 ) × ⋯ × ( a n + 1 ) \prod_{i = 0}^n(a_i+1)=(a_1+1)\times(a_2+1)\times\dots\times(a_n+1) i=0n(ai+1)=(a1+1)×(a2+1)××(an+1)

void NumDivisor(int n){
	map<int,int>ma;
	map<int,int>::iterator iter;
	ll res = 1;
	for(int i = 2; i <= n / i; i++){
		while(n % i == 0){
			n /= i;
			ma[i]++;
		}
	}
	if(n > 1) ma[n]++;
	for(iter = ma.begin(); iter != ma.end(); iter++){
		res = res * (iter->second + 1);
	} 
	cout << res;
} 
最大公约数

轻点一下有惊喜

如何求约数和

由约数定义我们可知 p 1 a 1 p_1^{a_1} p1a1的约数有: p 1 0 , p 1 1 , p 1 2 , . . . . p 1 a 1 p_1^0, p_1^1, p_1^2,....p_1^{a_1} p10,p11,p12,....p1a1,共 ( a 1 + 1 ) (a_1+1) (a1+1)个;同理 p 2 a 2 p_2^{a_2} p2a2的约数有 ( a 2 + 1 ) (a_2+1) (a2+1)个, … \dots p k a k p_k^{a_k} pkak的约数有 ( a k + 1 ) (a_k+1) (ak+1)个。而实际上 n n n的约数是在 p 1 a 1 , p 2 a 2 , … , p k a k p_1^{a_1},p_2^{a_2},\dots,p_k^{a_k} p1a1,p2a2,,pkak每个约数中分别挑选一个相乘得来,这样可知共有 ( a 1 + 1 ) × ( a 2 + 1 ) × ⋯ × ( a k + 1 ) (a_1+1)\times(a_2+1)\times\dots\times(a_k+1) (a1+1)×(a2+1)××(ak+1)种挑法,即约数的个数,有乘法原则我们可知它们的和为: f ( n ) = ( p 1 0 + p 1 1 + p 1 2 + … p 1 a 1 ) × ( p 2 0 + p 2 1 + p 2 2 + … p 2 a 2 ) … ( p k 0 + p k 1 + p k 2 + … p k a k ) f(n)=(p_1^0+p_1^1+p_1^2+…p_1^{a_1})\times(p_2^0+p_2^1+p_2^2+…p_2^{a_2})…(p_k^0+p_k^1+p_k^2+…p_k^{a_k}) f(n)=(p10+p11+p12+p1a1)×(p20+p21+p22+p2a2)(pk0+pk1+pk2+pkak)

ll fastpow(int a, int n){
	ll res = 1;
	while(n){
		if(n & 1) res = res * a;
		a = a * a;
		n >>= 1;
	}
	return res;
}

void SumDivisor(int n){
	ll res = 0, ans = 1;
	map<int,int>ma;
	map<int,int>::iterator iter;
	for(int i = 2;  i <= n / i; i++){
		while(n % i == 0){
			n /= i;
			ma[i]++;
		}
	}
	if(n > 1) ma[n]++; 
	for(iter = ma.begin(); iter != ma.end(); iter++){
		res = 0;
		for(int i = 0; i <= iter->second; i++){
			res = (res + fastpow(iter->first,i));
		}
		ans = ans * res;
	} 
	cout << ans;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星*湖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值