文章目录
一、约数
- 约数,又称因数。整数 a a a 除以整数 b b b( b ≠ 0 b≠0 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 的约数。一个整数的约数是有限的。同时,它可以在特定情况下成为公约数。
- 如果一个数 c c c 既是数 a a a 的因数,又是数 b b b 的因数,那么 c c c 叫做 a a a 与 b b b 的公因数。
- 两个数的公因数中最大的一个,叫做这两个数的最大公因数。
- 对于约数的求解,通常有以下几种方法:
- (1) 枚举法:将两个数的因数分别一一列出,从中找出其公因数,再从公因数中找出最大的一个,即为这两个数的最大公因数。
- (2) 短除法:大家都十分熟练的一种求解最大公因数的方法。
- (3) 分解质因数:将需要求最大公因数的两个数 A , B A,B A,B 分别分解质因数,再从中找出 A 、 B A、B A、B 公有的质因数,把这些公有的质因数相乘,即得 A 、 B A、B A、B 的最大公约数。
- (4) 辗转相除法(欧几里得算法):对要求最大公因数的两个数 a 、 b a、b a、b,设 b < a b<a b<a,先用 b b b 除 a a a,得 a = b q + r 1 ( 0 ≤ r 1 < b ) a=bq+r1(0≤r1<b) a=bq+r1(0≤r1<b)。若 r 1 = 0 r1=0 r1=0,则 ( a , b ) = b (a,b)=b (a,b)=b;若 r 1 ≠ 0 r1≠0 r1=0,则再用 r 1 r1 r1 除 b b b,得 b = r 1 q + r 2 ( 0 ≤ r 2 < r 1 ) b=r1q+r2 (0≤r2<r1) b=r1q+r2(0≤r2<r1),若 r 2 = 0 r2=0 r2=0,则 ( a , b ) = r 1 (a,b)=r1 (a,b)=r1,若 r 2 ≠ 0 r2≠0 r2=0,则继续用 r 2 r2 r2 除 r 1 r1 r1……如此循环,直到能整除为止。其最后一个非零余数即为 ( a , b ) (a,b) (a,b)。
二、试除法求约数
题目描述
给定 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 ≤ n ≤ 100
1≤n≤100
2
≤
a
i
≤
2
×
1
0
9
2 ≤ a_i ≤ 2×10^{9}
2≤ai≤2×109
输入样例
2
2
6
输出样例
1 2 3 6
1 2 4 8
具体实现
1. 实现思路
- 与试除法判断质数是相同的道理。
- 当 d d d 可以整除 n n n 时,显然, n / d n / d n/d 也可以整除 n n n。例如,当 n = 12 n = 12 n=12 时, 3 3 3 是 12 12 12 的约数, 4 4 4 也是 12 12 12 的约数,他们是成对存在的。
- 因此,在我们枚举的过程中,只需要枚举其中较小的一个即可,时间复杂度是 O ( n ) O(\sqrt{n}) O(n)。
- 用 vector 存储一个数的所有约数。
2. 实现代码
#include <bits/stdc++.h>
using namespace std;
vector<int> get_divisors(int x)
{
vector<int> res;
for (int i = 1; i <= x / i; i ++ )
{
if (x % i == 0)
{
res.push_back(i);
//判断边界情况
if (i != x / i)
{
res.push_back(x / i);
}
}
}
//对约数排序
sort(res.begin(), res.end());
return res;
}
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
cin >> x;
//自动对应数据类型
auto res = get_divisors(x);
for (auto x : res)
{
cout << x << ' ';
}
cout << endl;
}
return 0;
}
三、约数个数
题目描述
给定 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≤n≤100
1≤n≤100
2
≤
a
i
≤
2
×
1
0
9
2≤a_i≤2×10^{9}
2≤ai≤2×109
输入样例
3
2
6
8
输出样例
12
具体实现
1. 实现思路
- 一个数的约数是由这个数的几个质因子相乘得到的。
- 例如:12 的质因子有 2,3。12 的约数有:1,2,3,4,6,12。
- 约数 1 是由 0 个 2, 0 个 3 相乘得到的。
- 约数 2 是由 1 个 2, 0 个 3 相乘得到的。
- 约数 3 是由 0 个 2, 1 个3 相乘得到的。
- 约数 4 是由 2 个 2, 0 个3 相乘得到的。
- 约数 6 是由 1 个 2, 1 个3 相乘得到的。
- 约数 12 是由 2 个 2, 1 个 3相乘得到的。
- 12 可以分解为:22 × 31。所以 2 可以取 0 ~ 2个,3 种取法。3 可以取 0~1 个,2 种取法。12 的质因子一共:2 × 3 = 6 个,约数一共有:(2+1)×(1+1)=6 个。
- 关于约数个数和约数之和,有如下具体公式:
- 由上述公式,我们求解出每一个约数后,套用公式即可。
2. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 110, mod = 1e9 + 7;
int main()
{
int n;
cin >> n;
//第一个存储质因子的底数
//第二个存储质因子的指数
unordered_map<int, int> primes;
while (n -- )
{
int x;
cin >> x;
for (int i = 2; i <= x / i; i ++ )
{
while (x % i == 0)
{
x /= i;
primes[i] ++ ;
}
}
if (x > 1)
{
primes[x] ++ ;
}
}
LL res = 1;
for (auto p : primes)
{
res = res * (p.second + 1) % mod;
}
cout << res << endl;
return 0;
}
四、约数之和
题目描述
给定 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≤n≤100
1≤n≤100
2
≤
a
i
≤
2
×
1
0
9
2≤a_i≤2×10^{9}
2≤ai≤2×109
输入样例
3
2
6
8
输出样例
252
具体实现
1. 实现思路
- 关于约数之和,有如下计算公式:
- 与上一道题整体是差不多的,只是计算公式有所不同。
2. 实现代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 110, mod = 1e9 + 7;
int main()
{
int n;
cin >> n;
//第一个存储质因子的底数
//第二个存储质因子的指数
unordered_map<int, int> primes;
while (n -- )
{
int x;
cin >> x;
for (int i = 2; i <= x / i; i ++ )
{
while (x % i == 0)
{
x /= i;
primes[i] ++ ;
}
}
if (x > 1)
{
primes[x] ++ ;
}
}
LL res = 1;
for (auto p : primes)
{
LL a = p.first, b = p.second;
LL t = 1;
while (b -- )
{
t = (t * a + 1) % mod;
}
res = res * t % mod;
}
cout << res << endl;
return 0;
}
五、最大公约数(欧几里得算法、辗转相除法)
题目描述
给定 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≤n≤10^{5}
1≤n≤105
1
≤
a
i
,
b
i
≤
2
×
1
0
9
1≤a_i,b_i≤2×10^{9}
1≤ai,bi≤2×109
输入样例
2
3 6
4 6
输出样例
3
2
具体实现
1. 实现思路
- 最大公约数(Greatest Common Divisor)指两个或多个整数共有约数中最大的一个。也称最大公因数、最大公因子,a, b 的最大公约数记为(a,b),同样的,a,b,c 的最大公约数记为(a,b,c),多个整数的最大公约数也有同样的记号。
- 如果 d 可以整除 a,同时,d 也可以整除 b,那么,d 就可以整除 ax+by。
- 便可以得到如下公式:(a,b)=(b,a mod b)。
- 代码模板如下所示:
int gcd(int a, int b)
{
//返回a和b的最大公约数
return b ? gcd(b, a % b) : a;
}
2. 实现代码
#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b)
{
//返回a和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;
}