数论基础
数论基础部分
质数
定义: 在大于 的整数中,如果包含 和 本身这两个约数,那么这个数就是质数 (素数)。
- 质因数(素因数,质因子)在数论当中是指能够整除给定正整数的质数。
- 除 之外,两个没有其他共同 质因数的 的正整数称为互质。
- 与任何数互质。
- 正整数的因数分解可将正整数表示为一连串的质因子相乘,质因子如重复可以用指数表示。eg:
【质数数量】 在整个自然数集合中,质数的数量较少,分布稀疏,对于一个足够大的整数,不超过的质数大约有 个,即每 个数中大约有个质数。
试除法判断质数
若一个正整数 为合数,则存在一个能整除 的数 , 其中 。
即:
判定是否为质数的方法。让 去 模 到 的每一个数, 设枚举变量为 ,当 n % i == 0
成立时,则说明 不是质数。又因为有:当 可以整除 时, 也可以整除 ,所以枚举的边界就变为: ,即 。
时间复杂度
// 判断是否为质数
pub fn is_prime(n: usize) -> bool {
if n <= 2 { return false; }
let sqrt_n = (n as f32).sqrt() as usize;
for i in 2..sqrt_n {
if n % i == 0 {
return false;
}
}
true
}
bool is_prime(int n){
if(n < 2) return false;
for( int i = 2; i < n ; i++)
if(n % i == 0) // n 可以被 2~n 的整数整除
return false;
return true;
}
算术基本定理
任何一个大于 的自然数 , 如果 不为质数,那么 可以唯一分解成有限个质数的乘积。
这里 均为质数,其中指数 是正整数,且有
试除法分解质因数
对于 ~ 的每个数 ,若 能够整除 (即 n % i == 0
),则从 中除掉所有的因子 (i
为底数) ,同时累计除去的 的个数 (个数为指数)。
一个合数的合数因子一定在扫描到这个合数之前就从 中被除掉了. 根据算术基本定理, 那些较小的合数因子一定会被合数因子小的质数表示掉. 又因为我们枚举的 i
是从小到大递增的,所以当 n % i == 0
时, i
一定为质数 .
例子
对 进行质数分解:
12 / 2 = 6
6 / 2 = 3
3 / 2 = 1 (非整除,舍去)
3 / 3 = 1
12
从 2
开始被整除,12/2 = 6
, 然后看 6
能不能再被 2
整除,6/2=3
,然后看 3
能不能被 2
整除, 若不能,i + 1
, 然后循环往复.可以看到:12 的合数因子有 4
, 6
, 但是在 i
递增到 4
的时候,12
已经被表示为 2×2×3
了。
时间复杂度
pub fn prime_factors(mut n: usize) -> Vec<(usize, usize)> {
let mut v: Vec<(usize, usize)> = vec![];
let sqrt_n = (n as f32).sqrt() as usize;
for i in 2..sqrt_n + 1 {
let mut cnt: usize = 0;
if n % i == 0 {
while n % i == 0 {
n /= i;
cnt += 1;
}
v.push((i, cnt));
}
}
if n > 1 {
v.push((n, 1));
}
v
}
试除法求约数
若 是 的约数(),则 也是 的约数()。
即:
约数总是成对出现的(除了完全平方数, 会单独出现)。 因此,只需扫描 ~ ,尝试 能否整除 ,若能整除,则 也是 的约数,
试除法的推论: 一个整数 的约数上界为
时间复杂度: 。
pub fn get_divisors(n: usize) -> Vec<usize> {
let mut v: Vec<usize> = vec![];
let sqrt_n = (n as f32).sqrt() as usize;
for i in 1..sqrt_n + 1 {
if n % i == 0 {
v.push(i);
if i != n / i {
v.push(n / i);
}
}
}
v.sort();
v
}
算术基本定理的推论
在算术基本定理中,若整数 被唯一分解为 ,其中 都是正整数, 都是质数, 且满足 ,则 的正约数集合可写作: , 其中
正约数个数
- 个正约数个数为:
证明: 不同取法就对应着 不同的约数。取法的个数就是 约数的个数。 有 ~ 这些选择,共有 中选法。由乘法原理就可以得出约数的个数。
pub fn divisors_num(mut n: usize) -> u128 {
let mut mp: HashMap<usize, usize> = HashMap::new();
let sqrt_n = (n as f32).sqrt() as usize;
for i in 2..sqrt_n + 1 {
if n % i == 0 {
let mut cnt = 0;
while n % i == 0 {
n /= i;
cnt += 1;
}
mp.insert(i, cnt);
}
}
if n > 1 {
mp.insert(n, 1);
}
let mut res: u128 = 1;
for (_, v) in mp {
res = (res * (v + 1) as u128);
}
res
}
正约数之和
- 的所有正约数的和为:
证明: 在算术基本定理的推论中, 每个质因子的指数为 , 一个数的约数不止是质数,还有合数,而这些合数在算术基本定理中会被分解为 质数和质数的指数 。 可以对正约数之和的式子展开, 展开后为一定为: () + () + ... + ()
的形式。则每个 ()
就是约数.
秦九韶算法
pub fn divisors_sum(mut n: usize) -> usize {
let mut mp: HashMap<usize, usize> = HashMap::new();
let sqrt_n = (n as f32).sqrt() as usize;
for i in 2..sqrt_n + 1 {
if n % i == 0 {
let mut cnt = 0;
while n % i == 0 {
n /= i;
cnt += 1;
}
mp.insert(i, cnt);
}
}
if n > 1 {
mp.insert(n, 1);
}
let mut res: usize = 1;
for (k, mut v) in mp {
let mut t: usize = 1;
// 秦九韶算法
while v != 0 {
t = t * k + 1;
v -= 1;
}
res = res * t;
}
res
}