约数
约数
[AcWing869] 试除法求约数
题目描述
给定 \(n\) 个正整数 \(a_i\),对于每个整数 \(a_i\),请你按照从小到大的顺序输出它的所有约数。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个整数 \(a_i\)。
输出格式
输出共 \(n\) 行,其中第 \(i\) 行输出第 \(i\) 个整数 \(a_i\) 的所有约数。
数据范围
\(1 \le n \le 100\),
\(1 \le a_i \le 2 \times 10^9\)
输入样例:
2
6
8
输出样例:
1 2 3 6
1 2 4 8
算法
给定整数 \(a\) ,那么 \(i\) 就从 \(1\) 开始遍历,和质数类似,直到 \(i \leq a / i\) 结束。
如果 \(a\) 能整除 \(i\) 的情况下,结果添加\(i\) ,若 \(a/i\) 的结果不为 \(i\) ,就继续添加 \(a/i\) 。
C++ 代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
while (n--)
{
vector<int> ans;
int a; cin >> a;
for (int i = 1; i <= a / i; i++){
if (a % i == 0){
ans.push_back(i);
if (a / i != i) ans.push_back(a / i);
}
}
sort(ans.begin(), ans.end());
for (auto i : ans)
cout << i << " ";
cout << endl;
}
return 0;
}
时间复杂度 \(O(\sqrt n)\)
[AcWing870] 约数个数
题目描述
给定 \(n\) 个正整数 \(a_i\),请你输出这些数的乘积的约数个数,答案对 \(10^9+7\) 取模。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个整数 \(a_i\)。
输出格式
输出一个整数,表示所给正整数的乘积的约数个数,答案需对 \(10^9+7\) 取模。
数据范围
\(1 \le n \le 100\),
\(1 \le a_i \le 2 \times 10^9\)
输入样例:
3
2
6
8
输出样例:
12
算法
基本原理:约数个数定理
对于一个正整数 \(n(n>1)\) 可以分解质因数,得到
则 \(n\) 的正约数个数就是
其中 \(a_1,a_2,...,a_k\) 是 \(p_1,p_2,...,p_k\) 的指数。
定理证明:
首先 \(n\) 分解质因数得:\(n=p_{1}^{a_1}\cdot p_{2}^{a_2}\cdots p_{k}^{a_k}\) 。
由约数定义可得 \(p_{1}^{a_1}\) 的约数有 \(p_{1}^{0},p_{1}^{1},p_{1}^{2},...,p_{1}^{a_1}\) ,共 \(a_1 + 1\) 个;
同理 $ p_{2}^{a_2}$ 的约数有 \(p_{2}^{0},p_{2}^{1},p_{2}^{2},...,p_{2}^{a_2}\) ,共 \(a_2 + 1\) 个;
……
同理 $ p_{i}^{a_i}$ 的约数有 \(p_{i}^{0},p_{i}^{1},p_{i}^{2},...,p_{i}^{a_i}\) ,共 \(a_i + 1\) 个。
根据乘法原理,\(n\) 的约数的个数就是 \((a_1+1)(a_2+1)\cdots (a_k+1)\) 个。
C++ 代码
my code#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
int n; cin >> n;
unordered_map<int,int> hash;// hash存储质因数及其个数
while (n--){
int a; cin >> a;
for (int i = 2; i <= a / i; i++){
// 如果i是x的因子
while (a % i == 0){
a /= i;
hash[i]++;
}
}
// 最后没除尽的为最大因子,个数为1
if (a > 1) hash[a]++;
}
auto ans = 1ll;
// 因子利用时还有0次幂,所以有iter.second + 1个选择情况
for (auto iter : hash) ans = ans * (iter.second + 1) % mod;
cout << ans << endl;
return 0;
}
时间复杂度 \(O(\sqrt n)\)
[AcWing871] 约数之和
题目描述
给定 \(n\) 个正整数 \(a_i\),请你输出这些数的乘积的约数之和,答案对 \(10^9+7\) 取模。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个整数 \(a_i\)。
输出格式
输出一个整数,表示所给正整数的乘积的约数之和,答案需对 \(10^9+7\) 取模。
数据范围
\(1 \le n \le 100\),
\(1 \le a_i \le 2 \times 10^9\)
输入样例:
3
2
6
8
输出样例:
252
算法
基本原理:约数和定理
对于一个正整数 \(n(n>1)\) 可以分解质因数,得到
由正约数个数定理可知,\(n\) 的正约数个数为 \((a_1+1)(a_2+1)\cdots (a_k+1)\) 。
其中 \(a_1,a_2,...,a_k\) 是 \(p_1,p_2,...,p_k\) 的指数。
那么 \(n\) 的 \((a_1+1)(a_2+1)\cdots (a_k+1)\) 个正约数的和为
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int main()
{
int n; cin >> n;
unordered_map<int,int> hash;// hash存储质因数及其个数
while (n--){
int a; cin >> a;
for (int i = 2; i <= a / i; i++){
// 如果i是x的因子
while (a % i == 0){
a /= i;
hash[i]++;
}
}
// 最后没除尽的为最大因子,个数为1
if (a > 1) hash[a]++;
}
auto ans = 1ll;
for (auto iter : hash){
long long FI = iter.first, SE = iter.second;
auto t = 1ll;
// 这里类似于秦九韶算法
while (SE--) t = (t * FI+ 1) % mod;
ans = ans * t % mod;
}
cout << ans << endl;
return 0;
}
时间复杂度 \(O(\sqrt n)\)
[AcWing872] 最大公约数
题目描述
给定 \(n\) 对正整数 \(a_i, b_i\),请你求出每对数的最大公约数。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个整数对 \(a_i,b_i\)。
输出格式
输出共 \(n\) 行,每行输出一个整数对的最大公约数。
数据范围
\(1 \le n \le 10^5\),
\(1 \le a_i, b_i \le 2 \times 10^9\)
输入样例:
2
3 6
4 6
输出样例:
3
2
算法
老生常谈,辗转相除法。
正整数 \(a\) 和 \(b\) ,令 \((a,b)\) 为 \(a\) 和 \(b\) 的最大公约数。对 \(b\) 反复进行相除操作,如果 \(b\) 为 \(0\) 了,结束,此时 \(a\) 即为结果。
\((a,b)\) 在每次辗转相除中都会变为 \((b,a\%b)\) 。
C++ 代码
#include <bits/stdc++.h>
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;
}
时间复杂度 \(O(logn)\)