数学知识1.2
作者:互联网
一、简述
本文章主要介绍有关约数的基础算法。
二、约数
约数,又称因数。整数 \(a\) 除以整数 \(b\)(\(b\) ≠ 0) 除得的商正好是整数而没有余数,我们就说 \(a\) 能被 \(b\) 整除,或 \(b\) 能整除 \(a\)。\(a\) 称为 \(b\) 的倍数,\(b\) 称为 \(a\) 的约数。
三、试除法求约数
设一个数 \(n\),则我们只需从1遍历到 \(n\),把所有的整除 \(n\) 的数就是 \(n\) 的约数。
参考试除法判断质数,如果对于一个数 \(n\),若存在 \(d\) | \(n\)(\(d\) 整除 \(n\)),则 \(\frac{d}{n}\) | \(n\),基于此,我们可以对上面的算法进行优化,使得时间复杂度降到 O(\(\sqrt{n}\))。
模板题AcWing869.试除法求约数
题目描述
给定 \(n\) 个正整数 \(a{^{}_i}\),请你按照从小到大的顺序输出它的所有约数。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个正整数 \(a{^{}_i}\)。
输出格式
共 \(n\) 行,其中第 \(i\) 行输出第 \(i\) 个整数 \(a{^{}_i}\) 的所有约数。
数据范围
1≤ \(n\) ≤100,2≤ \(a{^{}_i}\) ≤210。
输入样例
2
6
8
输出样例
1 2 3 6
1 2 4 8
解题思路
试除法,并且对于平方数此类的数,我们要对它的约数进行去重,这里我们可以采用 set,同时 set 也可以实现自动排序,无需我们再对存放约数的数组进行排序。
C++代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
set<int> get_divisors(int x)
{
set<int> res;
for(int i = 1; i <= x / i; i ++)
{
if(x % i == 0)
{
res.insert(i);
res.insert(x / i);
}
}
return res;
}
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i ++)
{
int x;
cin >> x;
set<int> t = get_divisors(x);
for(auto v : t)
cout << v << ' ';
cout << endl;
}
return 0;
}
四、约数个数
- 算术基本定理:任何一个大于1的自然数 N,都可以唯一分解成有限个质数的乘积。
N = \(P{^{a^1}_1}\)\(P{^{a^2}_2}\)\(P{^{a^3}_3}\)⋅⋅⋅\(P{^{a^n}_n}\),这里 \(P{^{}_1}\) < \(P{^{}_2}\) < ⋅⋅⋅ < \(P{^{}_n}\) 且均为质数,其指数均是正整数。 - 约数个数 = (\(a{^{}_1}\) + 1) * (\(a{^{}_2}\) + 1) * ... * (\(a{^{}_n}\) + 1)。
模板题AcWing870. 约数个数
题目描述
给定 \(n\) 个正整数 \(a{^{}_i}\),请你输出这些数的乘积的约数个数,答案对 109+7 取模。
输入格式
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个正整数 \(a{^{}_i}\)。
输出格式
输出一个整数,表示所给正整数的乘积的约数个数,答案需对 109+7 取模。
数据范围
1≤ \(n\) ≤100,2≤ \(a{^{}_i}\) ≤2×109。
输入样例
3
2
6
8
输出样例
12
解题思路
试除法,因为我们要利用对应质因数的指数,我们使用哈希表存储。
C++代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 110, MOD = 1e9 + 7;
typedef long long LL;
int n;
unordered_map<int, int> primes;
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
int x;
cin >> x;
for(int j = 2; j <= x / j; j ++)
{
while(x % j == 0)
{
x /= j;
primes[j] ++;
}
}
if(x > 1) primes[x] ++;
}
LL res = 1;
for(auto [k, v] : primes)
{
res = (res * (v + 1)) % MOD;
}
cout << res;
return 0;
}
五、约数之和
约数之和的依据也是算术基本定理。
约数之和 = (\(P{^{0}_1}\) + \(P{^{2}_1}\) + ... + \(P{^{a^1}_1}\)) * (\(P{^{0}_2}\) + \(P{^{2}_2}\) + ... + \(P{^{a^1}_2}\)) * ... * (\(P{^{0}_n}\) + \(P{^{2}_n}\) + ... + \(P{^{a^1}_n}\))。
模板题AcWing871.约数之和
题目描述
给定 \(n\) 个正整数 \(a{^{}_i}\),请你输出这些数的乘积的约数之和,答案对 109+7 取模。
输入格式
共一行,包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个整数 \(a{^{}_i}\)。
输出格式
输出一个整数,表示所给正整数的乘积的约数之和,答案需对 109+7 取模。
数据范围
1≤ \(n\) ≤106。
输入样例
3
2
6
8
输出样例
252
解题思路
参考前面试除法计算约数个数,我们利用哈希表存储质因数及其指数之后,对质因数 \(P{^{}_i}\) 及其指数 \(a{^{}_i}\) 计算 \(P{^{0}_i}\) + \(P{^{2}_i}\) + ... + \(P{^{a^i}_i}\),将所有的结果累乘即可。
C++代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 110, MOD = 1e9 + 7;
typedef long long LL;
int n;
unordered_map<int, int> primes;
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++)
{
int x;
cin >> x;
for(int j = 2; j <= x / j; j ++)
{
while(x % j == 0)
{
x /= j;
primes[j] ++;
}
}
if(x > 1) primes[x] ++;
}
LL res = 1;
for(auto [k, v] : primes)
{
LL t = 1;
int p = k, a = v;
while(a --)
{
t = (t * p + 1) % MOD;
}
res = (res * t) % MOD;
}
cout << res;
return 0;
}
六、最大公约数
计算两个数的最大公约数我们常使用的算法是辗转相除法(欧几里得算法)。
核心思想:如果 \(d\) | \(a\),\(d\) | \(b\),则 \(d\) | \(x*a+y*b\),这里 \(x\) 和 \(y\) 都是整数。
欧几里得算法的表示:(\(a\),\(b\)) = (\(b\),\(a\) \(mod\) \(b\)),\(mod\) 是求余操作,等号表示左右的最大公约数相等。
证明:首先 \(a\) \(mod\) \(b\) = \(a\) - \(\frac{a}{b} * b\) = \(a\) - \(c * b\),这里 \(\frac{a}{b}\) 是整除,设最大公约数是 \(d\)。
- 左->右:\(d\) | \(a\),\(d\) | \(b\),则 \(d\) | \(b\),\(d\) | \(a-c*b\),等号成立。
- 右->左:\(d\) | \(b\),\(d\) | \(a-c*b\),则\(d\) | \(a-c*b+c*b\) 也就是 \(d\) | \(a\)且\(d\) | \(b\),等号成立。
证毕。
模板题AcWing872.最大公约数
题目描述
给定 \(n\) 对正整数 \(a{^{}_i}\),\(b{^{}_i}\),请你求出每对数的最大公约数。
输入格式
共一行,包含整数 \(n\)。
接下来 \(n\) 行,每行一对正整数 \(a{^{}_i}\),\(b{^{}_i}\)。
输出格式
输出共 \(n\) 行,每行输出一个整数对的最大公约数。
数据范围
1≤ \(n\) ≤ 105,
1≤ \(a{^{}_i}\),\(b{^{}_i}\) ≤ 2×109。
输入样例
2
3 6
4 6
输出样例
3
2
解题思路
辗转相除法。
C++代码
#include <iostream>
using namespace std;
int gcd(int a, int b)
{
if(a % b == 0) return b;
return gcd(b, a % b);
}
int n;
int main()
{
cin >> n;
while(n --)
{
int a, b;
cin >> a >> b;
printf("%d\n", gcd(a, b));
}
return 0;
}
标签:约数,输出,正整数,1.2,int,整数,数学知识,include 来源: https://www.cnblogs.com/Cocoicobird/p/16695044.html