约数(试除法求约数 约数个数 约数之和 最大公约数)

目录

  • 一、试除法求约数
    • 典型例题
    • 代码实现
  • 二、约数个数
    • 思路分析
    • 典型例题
    • 代码实现
  • 三、约数之和
    • 思路分析
    • 典型例题
    • 代码实现
  • 四、最大公约数
    • 思路分析
    • 典型例题
    • 代码实现


一、试除法求约数

典型例题

题目描述:
给定 n n n 个正整数 a i a_i ai,对于每个整数 a i a_i ai,请你按照从小到大的顺序输出它的所有约数。

输入格式:
第一行包含整数 n n n

接下来 n n n 行,每行包含一个整数 a i a_i ai

输出格式:
输出共 n n n 行,其中第 i i i 行输出第 i i i 个整数 a i a_i ai 的所有约数。

数据范围:
1 ≤ n ≤ 100 , 1 ≤ a i ≤ 2 ∗ 1 0 9 1≤n≤100,1≤a_i≤2*10^9 1n100,1ai2109

输入样例:

2
6
8

输出样例:

1 2 3 6 
1 2 4 8 

代码实现

#define _CRT_NO_SECURE_WARNINGS
#include
#include
#include

using namespace std;

vector<int> get_divisors(int n)
{
	vector<int> res;
	for (int i = 1; i <= n / i; ++i)
	{
		if (n % i == 0)
		{
			res.push_back(i);
			if (i != n / i) res.push_back(n / i);
		}
	}
	sort(res.begin(), res.end());
	return res;
}
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int a;
		cin >> a;
		auto res = get_divisors(a);
		for (auto e : res) cout << e << ' ';
		cout << endl;
	}
	return 0;
}

整体时间复杂度: O ( n ) O(\sqrt n) O(n )

a a a b b b 的约数 ⇒ b b b a a a 的倍数

因此,要计算 1 1 1 ~ n n n 的所有约数,可以通过计算每个数在范围内的其倍数的数目来得到。
n 1 + n 2 + n 3 + . . . + n n ⇒ n log ⁡ n \frac{n}{1} + \frac{n}{2} + \frac{n}{3}+ ... + \frac{n}{n} ⇒ n \log n 1n+2n+3n+...+nnnlogn

所以每个数的平均约数为 log ⁡ n \log n logn

快速排序的时间复杂度: O ( log ⁡ n log ⁡ log ⁡ n ) O(\log n \log \log n) O(lognloglogn)


二、约数个数

思路分析

由算数的基本定理,可得 n n n 的唯一分解式:
n = P 1 r 1 ∗ P 2 r 2 ∗ . . . ∗ P k r k n = P_1^{r_1}*P_2^{r_2}*...*P_k^{r_k} n=P1r1P2r2...Pkrk

n n n 的约数个数公式:
φ ( n ) = ( r 1 + 1 ) ∗ ( r 2 + 1 ) ∗ . . . ∗ ( r k + 1 ) φ(n) = (r_1 + 1)*(r_2 + 1)*...*(r_k + 1) φ(n)=(r1+1)(r2+1)...(rk+1)

证明:

P 1 P_1 P1 为例,这个质数因子,可以选择 0 0 0 个,可以选择 1 1 1 个等等,最多可以选择 r 1 r_1 r1 个,就是有 r 1 + 1 r_1+1 r1+1 种选择的可能性,对 P 2 , P 3 , . . . , P k P_2,P_3,...,P_k P2,P3,...,Pk 也都是如此,根据乘法原理,所有的可能性就是 ( r 1 + 1 ) ∗ ( r 2 + 1 ) ∗ . . . ∗ ( r k + 1 ) (r_1+1)*(r_2+1)*...*(r_k+1) (r1+1)(r2+1)...(rk+1)

例如:

180 = 2 2 ∗ 3 2 ∗ 5 180=2^2∗3^2∗5 180=22325
φ ( 180 ) = ( 2 + 1 ) ∗ ( 2 + 1 ) ∗ ( 1 + 1 ) = 18 φ(180)=(2+1)∗(2+1)∗(1+1)=18 φ(180)=(2+1)(2+1)(1+1)=18


典型例题

题目描述:
给定 n n n 个正整数 a i a_i ai,请你输出这些数的乘积的约数个数,答案对 1 0 9 + 7 10^9+7 109+7 取模。

输入格式:
第一行包含整数 n n n

接下来 n n n 行,每行包含一个整数 a i a_i ai

输出格式:
输出一个整数,表示所给正整数的乘积的约数个数,答案需对 109 + 7 109+7 109+7 取模。

数据范围:
1 ≤ n ≤ 100 , 1 ≤ a i ≤ 2 × 1 0 9 1≤n≤100,1≤a_i≤2×10^9 1n100,1ai2×109

输入样例:

3
2
6
8

输出样例:

12

代码实现

#define _CRT_NO_SECURE_WARNINGS
#include
#include

using namespace std;

unordered_map<int, int> primes;
void divide(int n)
{
	for (int i = 2; i <= n / i; ++i)
	{
		while (n % i == 0)
		{
			primes[i]++;
			n /= i;
		}
	}
	if (n > 1) primes[n]++;
}
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int a;
		cin >> a;
		divide(a);
	}
	long long res = 1;
	for (auto t : primes) res *= (t.second + 1) % ((int)1e9 + 7);
	cout << res << endl;
	return 0;
}

三、约数之和

思路分析

约数之和的公式:
( P 1 0 + P 1 1 + P 1 2 + . . . + P 1 r 1 ) ∗ . . . ∗ ( P k 0 + P k 1 + P k 2 + . . . + P k r k ) (P_1^{0} + P_1^{1} + P_1^{2} + ... + P_1^{r_1})*...*(P_k^{0} + P_k^{1} + P_k^{2} + ... + P_k^{r_k}) (P10+P11+P12+...+P1r1)...(Pk0+Pk1+Pk2+...+Pkrk)
通过排列组列便可以得出所有约数之和


典型例题

题目描述:
给定 n n n 个正整数 a i a_i ai,请你输出这些数的乘积的约数之和,答案对 1 0 9 + 7 10^9+7 109+7 取模。

输入格式:
第一行包含整数 n n n

接下来 n n n 行,每行包含一个整数 a i a_i ai

输出格式:
输出一个整数,表示所给正整数的乘积的约数之和,答案需对 1 0 9 + 7 10^9+7 109+7 取模。

数据范围:
1 ≤ n ≤ 100 , 1 ≤ a i ≤ 2 × 1 0 9 1≤n≤100,1≤a_i≤2×10^9 1n100,1ai2×109

输入样例:

3
2
6
8

输出样例:

252

代码实现

#define _CRT_NO_SECURE_WARNINGS
#include
#include

using namespace std;

unordered_map<int, int> primes;
const int mod = 1e9 + 7;
void divide(int n)
{
	for (int i = 2; i <= n / i; ++i)
	{
		while (n % i == 0)
		{
			primes[i]++;
			n /= i;
		}
	}
	if (n > 1) primes[n]++;
}
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int a;
		cin >> a;
		divide(a);
	}
	long long res = 1;
	for (auto t : primes)
	{
		long a = t.first, b = t.second, e = 1;
		while (b--) e = (e * a + 1) % mod;
		res = res * e % mod;
	}
	cout << res << endl;
	return 0;
}

四、最大公约数

思路分析

欧几里得算法(辗转相除法)

a a a 为被除数, b b b 为除数,若 d ∣ a d|a da d ∣ b d|b db,则: d ∣ ( a + b ) d|(a+b) d(a+b) d ∣ ( a ∗ x + b ∗ y ) d|(a∗x+b∗y) d(ax+by)

余数 r = a − k ∗ b r = a - k*b r=akb ( k ∈ Z k∈Z kZ),由于 a a a b b b 均为 d d d 的倍数,所以可以得到 d ∣ r d|r dr

( a , b ) (a,b) (a,b) 代表 a a a b b b 的最大公约数,可得 ( a , b ) = ( b , r ) (a,b)=(b,r) (a,b)=(b,r)

故而:

(a,b) =(b, a % b)

典型例题

题目描述:
给定 n n n 对正整数 a i , b i a_i,b_i ai,bi,请你求出每对数的最大公约数。

输入格式:
第一行包含整数 n n n

接下来 n n n 行,每行包含一个整数对 a i , b i a_i,b_i ai,bi

输出格式:
输出共 n n n 行,每行输出一个整数对的最大公约数。

数据范围:
1 ≤ n ≤ 1 0 5 , 1 ≤ a i , b i ≤ 2 × 1 0 9 1≤n≤10^5,1≤a_i,b_i≤2×10^9 1n105,1ai,bi2×109

输入样例:

2
3 6
4 6

输出样例:

3
2

代码实现

#define _CRT_NO_SECURE_WARNINGS
#include
using namespace std;

int gcd(int a, int b)
{
	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;
}

你可能感兴趣的:(从零开始的算法打灰,c++,算法)