第四章 数学知识 约数相关

1、求一个数的所有约数

使用试除法,如果 n 能整除 d, 则 n 也能整除 n / d,所以只需要遍历1~ n \sqrt{n} n 即可获得所有约数

vector<int> ans;
for(int i = 1; i <= n / i; i ++)
{
	if(n % i == 0)
	{
		ans.push_back(i);
		if(i != n / i) ans.push_back(n / i);
	}
}

2、求一个数所有约数的个数

首先将数N分解质因数为 p 1 k 1 p 2 k 2 p 3 k 3 . . . p n k n p_1^{k_1}p_2^{k_2}p_3^{k_3}...p_n^{k_n} p1k1p2k2p3k3...pnkn
对于N的每个约数都可以写成 p 1 b 1 p 2 b 2 p 3 b 3 . . . p n b n p_1^{b_1}p_2^{b_2}p_3^{b_3}...p_n^{b_n} p1b1p2b2p3b3...pnbn,通过变换 b 1 b_1 b1 b n b_n bn的数值,就可以变成不同的约数。
所以所有约数的数量就是所有 b 1 b 2 b 3 b 4 . . . b n b_1b_2b_3b_4...b_n b1b2b3b4...bn的不同组合的数量。其中 b 1 b_1 b1的取值范围为0到 k 1 k_1 k1 b 2 b_2 b2为0到 k 2 k_2 k2,以此类推。
所有所有约数的数量K = ( k 1 + 1 ) ( k 2 + 1 ) . . . ( k n + 1 ) (k_1 + 1)(k_2 + 1)...(k_n + 1) (k1+1)(k2+1)...(kn+1)

unordered_map<int,int> mp;
for(int i = 2; i <= n / i; i ++ )
{
	if(n % i == 0)
	{
		while(n % i == 0)
		{
			n /= i;
			mp[i] ++;
		}
	}
	if(n > 1) mp[n] ++;
}
long long res = 1;
for(auto p : mp)
{
	res = res * (1 + p.second);
}

3、求一个数的所有约数之和

首先将数N分解质因数为 p 1 k 1 p 2 k 2 p 3 k 3 . . . p n k n p_1^{k_1}p_2^{k_2}p_3^{k_3}...p_n^{k_n} p1k1p2k2p3k3...pnkn
对于N的每个约数都可以写成 p 1 b 1 p 2 b 2 p 3 b 3 . . . p n b n p_1^{b_1}p_2^{b_2}p_3^{b_3}...p_n^{b_n} p1b1p2b2p3b3...pnbn,通过变换 b 1 b_1 b1 b n b_n bn的数值,就可以变成不同的约数
在此之上,其实求和SUM就是求
∑ 0 k 1 ∑ 0 k 2 ∑ 0 k 3 . . . ∑ 0 k n p 1 b 1 p 2 b 2 p 3 b 3 . . . p n b n \sum_0^{k1}\sum_0^{k2}\sum_0^{k3}...\sum_0^{kn}p_1^{b_1}p_2^{b_2}p_3^{b_3}...p_n^{b_n} 0k10k20k3...0knp1b1p2b2p3b3...pnbn整理后得到
( p 1 0 + p 1 1 + p 1 2 + p 1 3 + . . . p 1 k 1 ) ( p 2 0 + p 2 1 + p 2 2 + p 2 3 + . . . p 2 k 1 ) . . . ( p n 0 + p n 1 + p n 2 + p n 3 + . . . p n k 1 ) (p_1^0 + p_1^{1} + p_1^{2}+ p_1^{3}+...p_1^{k_1})(p_2^0 + p_2^{1} + p_2^{2}+ p_2^{3}+...p_2^{k_1})...(p_n^0 + p_n^{1} + p_n^{2}+ p_n^{3}+...p_n^{k_1}) (p10+p11+p12+p13+...p1k1)(p20+p21+p22+p23+...p2k1)...(pn0+pn1+pn2+pn3+...pnk1)

unordered_map<int,int> mp;
for(int i = 2; i <= n / i; i ++ )
{
	if(n % i == 0)
	{
		while(n % i == 0)
		{
			n /= i;
			mp[i] ++;
		}
	}
	if(n > 1) mp[n] ++;
}
long long res = 1;
for(auto p : mp)
{
    long long sum = 1;
    for(int i = 0; i < p.second; i ++)
    {
    	sum = sum * p.first + 1;
    }
	res = res * sum;
}

4、最大公因数

给定两个数a、b求两个数的最大公因数
设两个正整数 a 和 b 的 最大公约数 d,则有 gcd(a,b) = gcd(b,a%b)
证明:
设a%b = a - k*b 其中k = a/b(向下取整)

  • 若d是(a,b)的公约数 则知 d|a 且 d|b 则易知 d|a-k*b 故d也是(b,a%b) 的公约数
  • 若d是(b,a%b)的公约数 则知 d|b 且 d|a-kb 则 d|a-kb+k*b = d|a 故而d|b 故而 d也是(a,b)的公约数

因此(a,b)的公约数集合和(b,a%b)的公约数集合相同 所以他们的最大公约数也相同
资料来源

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

参考资料

  1. Acwing
  2. 最大公因数证明
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值