算法基础-质数-约数

算法基础-数论

      • 质数
      • 约数

数论(英语:Number theory)是纯粹数学的分支之一,主要研究整数的性质,被称为“最纯”的数学领域。

质数

质数(Prime number),又称素数,指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个正因数的数)。大于1的自然数若不是素数,则称之为合数(也称为合成数)。

题型一:判断某个正整数是否为质数

做法:

  • 暴力循环 时间复杂度:O(n)
bool get_prime(int x)
{
  if (x < 2) return false;
  for (int i = 2; i < x; i++)
    if (x % i == 0) return false;
 	return true;
}
  • 试除法 时间复杂度:O(sqrt(n))
bool get_prime(int x)
{
  if (x < 2) return false;
  for (int i = 2; i <= x / i; i++)
    if (x % i == 0) return false;
 	return true;
} 

这里要优化利用到了: 如果 x $ a == 0 ,那么 x / a = b , x / b = a ,从而不用全部循环一遍。

有三种循环的方式:

for (int i = 2; i <= sqrt(n); i++) // sqrt(n) 比较慢
for (int i = 2; i * i <= n; i++) // i * i 有溢出风险
for (int i = 2; i <= n / i; i++) // 建议这种方式

题型二:将某个正整数分解为质因数

做法:

  • 试除法
// 输出的 i 为质因子, s 为次数
void divide(int x)
{
  if (x < 2) return;
  
  for (int i = 2; i <= x / i; i++)
  {
    int s = 0;
    if (x % i == 0)
    {
      while (x % i == 0)
      {
        s ++;
        x /= i;
      }
      printf("%d %d\n", i, s);
    }
  }
  if (x > 1) printf("%d %d", x, 1);
  
  return;
}

题型三:在 1 ~ n 的范围中筛选质数

做法:

  • 暴力筛法
// primes[] 存储质因子
// cnt 存储质因子的个数
// st[] 筛除不是质因子

int primes[N], cnt;
bool st[N];

void get_primes(int x)
{
  for (int i = 2; i <= x; i++)
  {
    if (!st[i]) primes[cnt++] = i;
    for (int j = i + i; j <= x; j += i) st[j] = true;
  }
}
  • 埃式筛法
int primes[N], cnt;
bool st[N];

void get_primes(int x)
{
  for (int i = 2; i <= x; i++)
  {
    if (!st[i])
    {
      primes[cnt++] = i;
      for (int j = i + i; j <= x; j += i) st[j] = true;
    }
  }
}
  • 线性筛法 : n 只会被最小质因子筛掉。
int primes[N], cnt;
bool st[N];

void get_primes(int x)
{
  for (int i = 2; i <= x; i++)
  {
    if (!st[i]) primes[cnt++] = i;
    for (int j = 0; primes[j] <= x / i; j++)
    {
      st[primes[j] * i] = true;
      if (i % primes[j] == 0) break;
    }
  }
}

约数

因数(英语:factor)也称 约数因子除子,是一个常见的数学名词,用于描述自然数 a \displaystyle a a 和自然数 b \displaystyle b b 之间存在的整除关系,即可 b \displaystyle b b 以被 a \displaystyle a a 整除。这里我们称 b \displaystyle b b a \displaystyle a a 的倍数, a \displaystyle a a b \displaystyle b b 的因数或因子。

题型一:求一个数的所有约数

做法:

  • 暴力枚举
vector get_divisor(int x)
{
    vector res;
    for (int i = 1; i <= x; i++)
    {
        if (x % i == 0) res.push_back(i);
    }
    
    sort(res.begin(), res.end());
    return res;
}
  • 试除法
vector get_divisor(int x)
{
    vector 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;
}

题型二:求一个数中所有约数的个数

做法:

  1. 先分解质因子。
  2. 再对所有质因子的指数加一,再相乘。

题型三:求一个数中所有约数之和

做法:

  1. 先分解质因子。如果 N = p 0 a ∗ p 1 b ∗ p 2 c ∗ p 3 d N = p_{0}^{a} * p_{1}^{b} * p_{2}^{c} * p_{3}^{d} N=p0ap1bp2cp3d
  2. 再计算 ( p 0 0 + p 0 1 + ∗ ∗ ∗ + p 0 a ) × ∗ ∗ ∗ × ( p 3 0 + p 3 1 + ∗ ∗ ∗ + p 3 d ) (p_{0}^{0}+p_{0}^{1}+ *** +p_{0}^{a}) \times *** \times (p_{3}^{0}+p_{3}^{1}+ *** +p_{3}^{d}) (p00+p01++p0a)××(p30+p31++p3d)

注意:由于答案一般比较大,所以常常会取模。

题型四:求最大公约数(欧几里得算法 | 辗转相除法)

int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}

你可能感兴趣的:(算法)