数论基础

Hdd数论算法数论算法大约 5 分钟...

数论基础部分

质数

定义: 在大于 11 的整数中,如果包含 11 和 本身这两个约数,那么这个数就是质数 (素数)。

  • 质因数(素因数,质因子)在数论当中是指能够整除给定正整数的质数。
  • 11 之外,两个没有其他共同 质因数的 的正整数称为互质。
  • 11 与任何数互质。
  • 正整数的因数分解可将正整数表示为一连串的质因子相乘,质因子如重复可以用指数表示。eg: 12=2×2×3=22×312=2×2×3=2^2×3

【质数数量】 在整个自然数集合中,质数的数量较少,分布稀疏,对于一个足够大的整数NN,不超过NN的质数大约有 NlnN\frac{N}{lnN} 个,即每 lnNlnN 个数中大约有11个质数。

试除法判断质数

若一个正整数 NN 为合数,则存在一个能整除 NN 的数 TT, 其中 2Tsqrt(n)2≤T≤sqrt(n)

即:

​ 判定是否为质数的方法。让 nn 去 模 22nn 的每一个数, 设枚举变量为 ii ,当 n % i == 0 成立时,则说明 nn 不是质数。又因为有:当 ii 可以整除 nn 时, ni\frac{n}{i} 也可以整除 nn,所以枚举的边界就变为: inii ≤ \frac {n} {i} ,即 i2ni^2 ≤ n

时间复杂度 o(sqrt(n))o(sqrt(n))

// 判断是否为质数
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
}

算术基本定理

任何一个大于 11 的自然数 NN , 如果 NN 不为质数,那么 NN 可以唯一分解成有限个质数的乘积。

N=p1a1×p2a2×p3a3×...×pnan N = p_1^{a_1}×p_2^{a_2}×p_3^{a_3}×...×p_n^{a_n}

这里 pip_i 均为质数,其中指数 aia_i 是正整数,且有 p1<p2<p3...<pnp_1<p_2<p_3...<p_n

试除法分解质因数

​ 对于 22 ~ sqrt(n)⌊sqrt(n)⌋ 的每个数 ii ,若 ii 能够整除 nn (即 n % i == 0),则从 nn 中除掉所有的因子 ii (i为底数) ,同时累计除去的 ii 的个数 (个数为指数)。

​ 一个合数的合数因子一定在扫描到这个合数nn之前就从 nn 中被除掉了. 根据算术基本定理, 那些较小的合数因子一定会被合数因子小的质数表示掉. 又因为我们枚举的 i 是从小到大递增的,所以当 n % i == 0 时, i 一定为质数 .

例子

1212 进行质数分解:

12 / 2  =  6
6  / 2  =  3
3  / 2  =  1 (非整除,舍去)
3  / 3  =  1

122 开始被整除,12/2 = 6, 然后看 6 能不能再被 2 整除,6/2=3 ,然后看 3 能不能被 2 整除, 若不能,i + 1, 然后循环往复.可以看到:12 的合数因子有 4 6, 但是在 i 递增到 4 的时候,12 已经被表示为 2×2×3 了。

时间复杂度 o(sqrt(n))o(sqrt(n))

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
}

试除法求约数

ddNN 的约数(dsqrt(N)d≥sqrt(N)),则 N/dN/d 也是 NN 的约数(N/dNN/d≤N)。

即:

​ 约数总是成对出现的(除了完全平方数,sqrt(N)sqrt(N) 会单独出现)。 因此,只需扫描 d=1d = 1~sqrt(N)sqrt(N) ,尝试 dd 能否整除 NN ,若能整除,则 N/dN/d 也是 NN 的约数,

试除法的推论: 一个整数 NN 的约数上界为 2sqrt(N)2sqrt(N)

时间复杂度: O(sqrt(N))O(sqrt(N))

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
}

算术基本定理的推论

​ 在算术基本定理中,若整数 NN 被唯一分解为 N=p1c1×p2c2...pmcmN=p_1^{c_1}×p_2^{c_2}...p_m^{c_m} ,其中 cic_i 都是正整数, pip_i 都是质数, 且满足 p1<p2<...<pmp_1<p_2<...<p_m ,则 NN正约数集合可写作: {p1b1×p2b2×...×pmbm}\{p_1^{b_1}×p_2^{b_2}×...×p_m^{b_m}\}, 其中 0bici0≤b_i≤c_i

正约数个数

  1. NN正约数个数为:

i=1m(ci+1)=(c1+1)×(c2+1)×...×(cm+1) \prod\limits_{i=1}^{m}(c_i+1)=(c_1+1)×(c_2+1)×...×(c_m+1)

证明: ​ b1...bmb_1 ... b_m 不同取法就对应着 不同的约数。取法的个数就是 约数的个数。 b1b_100 ~ c1c_1 这些选择,共有 c1+1c_1 + 1 中选法。由乘法原理就可以得出约数的个数。

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
}

正约数之和

  1. NN所有正约数的和为:

i=1m(j=0ci(pi)j)=(1+p1+p12+...p1c1)×...×(1+pm+pm2+...+pmcm) \prod\limits_{i=1}^{m} \Bigg(\sum_{j=0}^{c_i}(p_i)^j\Bigg) =(1+p_1+p_1^2+...p_1^{c_1})×...×(1+p_m+p_m^2+...+p_m^{c_m})

证明: 在算术基本定理的推论中, 每个质因子的指数为 bib_i, 一个数的约数不止是质数,还有合数,而这些合数在算术基本定理中会被分解为 质数和质数的指数 。 可以对正约数之和的式子展开, 展开后为一定为: () + () + ... + () 的形式。则每个 () 就是约数.

秦九韶算法

f(x)=anxn+an1xn1+...+a1x+a0=(...((anx+an1)x+an2)x+...+a1)x+a0f(x) = a_nx^n + a_{n-1}x^{n-1} + ... + a_1x + a_0=(...((a_nx + a_{n-1})x+a_{n-2})x+...+a_1)x+a_0

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
}
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.14.9