【知识点】数论入门基础

预备知识

最大公约数

代码为:__gcd(a,b)

最小公倍数

代码为:a/__gcd(a,b)*b

互素

又名互质、既约。
gcd(a1,a2,a3,...,an) = 1则称a1到an所有数互素。
注意,多个数互素,不一定就两两互素。例如6,10,15互素,但两两都不互素。

素数与合数

设整数p满足p不为0、1、-1,若p没有平凡约数外的其他约数,则称为素数(质数)。
注意,一般情况下,若无特殊说明,素数指正的素数。
若整数p满足p不为0、1、-1,且p不是素数,则p为合数。
特殊性质:所有大于3的素数都可以表示为6n+1或6n-1的形式。

素数-素性测试

素性测试分两种:

  • 确定性测试:绝对确定一个数是否为素数。
  • 概率性测试:比确定性测试快很多,但得到的伪素数也可能是合数。

试除法

bool isPrime(int a) {
  if (a < 2) return 0;
  for (int i = 2; (long long)i * i <= a; ++i)  // 防溢出
    if (a % i == 0) return 0;
  return 1;
}

Fermat素性测试

最简单的一种概率性测试方法,借助费马小定理。核心思想是:
不断选取[2,n-1]中的基a,并检验是否每次都有\(a^{n - 1} \equiv 1 \pmod{n}\).

bool millerRabin(int n) {
  if (n < 3) return n == 2;
  // test_time 为测试次数,建议设为不小于 8
  // 的整数以保证正确率,但也不宜过大,否则会影响效率
  for (int i = 1; i <= test_time; ++i) {
    int a = rand() % (n - 2) + 2;
    if (quickPow(a, n - 1, n) != 1) return false;
  }
  return true;
}

当然,即使满足了\(a^{n - 1} \equiv 1 \pmod{n}\)的n也不一定是素数。比如341=11*31 是合数,但选择a=2时,\(2^{340} \equiv 1 \pmod{341}\),这时n称为伪素数。

最大公约数算法

欧几里得算法

即辗转相除法。\(\gcd(a, b) = \gcd(b, a \bmod b)\)

int gcd(int a, int b) {
  if (b == 0) return a;
  return gcd(b, a % b);
}

在输入两个长为n的二进制整数时,欧几里得算法的时间复杂度为O(n),换句话说,在默认a和b是同阶的情况下,时间复杂度为O(log max(a, b))

更相减损术

gcd(a, b) = gcd(a-b, b)

int gcd(int a, int b) {
  if (b == 0) return a;
  return gcd(b, a - b);
}

更相减损术的时间复杂度为O(n)

Stein算法

如果a>>b,那么更相损减术的时间复杂度将达到最坏情况。
进行优化:
如果2|a2|b,则gcd(a, b) = 2gcd(a/2, b/2)
否则如果2|a(2|b同理),则gcd(a, b) = gcd(a/2, b)
Stein算法的时间复杂度为O(logn)

求多个数的最大公约数

每次将前两项的最大公约数放回数列中,删除原两项,重复此操作直到数列中只剩下一项,即为最大公约数。

最小公倍数算法

两个数的最小公倍数

lcm(a, b) = (a * b) / gcd(a, b)

为了避免溢出,经常先除后乘来计算。

多个数的最小公倍数

每次将前两项的最小公倍数放回数列中,删除原两项,重复此操作直到数列中只剩下一项,即为最小公倍数。

扩展欧几里得算法

扩展欧几里得算法,常用于求ax + by = gcd(a, b)的一组可行解。
b = 0时,解为x = 1, y = 0

否则:


\(ax_1 + by_1 = \gcd(a,b)\)

\(bx_2 + (a \mod b)y_2 = \gcd(b, a \mod b)\)

由欧几里得定理可知:\(\gcd(a,b) = \gcd(b, a \mod b)\)

所以 \(ax_1 + by_1 = bx_2 + (a \mod b)y_2\)

又因为 \(a \mod b = a - \left(\left\lfloor \frac{a}{b} \right\rfloor \times b\right)\)

所以 \(ax_1 + by_1 = bx_2 + \left(a - \left\lfloor \frac{a}{b} \right\rfloor \times b\right)y_2\)

\(ax_1 + by_1 = ay_2 + bx_2 - \left\lfloor \frac{a}{b} \right\rfloor \times by_2 = ay_2 + b\left(x_2 - \left\lfloor \frac{a}{b} \right\rfloor y_2\right)\)

因为 \(a = a,b = b\)

所以 \(x_1 = y_2, y_1 = x_2 - \left\lfloor \frac{a}{b} \right\rfloor y_2\)

将x2, y2不断代入递归求解,直到回到x = 1, y = 0的基础情况。

代码实现:

int Exgcd(int a, int b, int &x, int &y) {
  if (!b) {
    x = 1;
    y = 0;
    return a;
  }
  int d = Exgcd(b, a % b, x, y);
  int t = x;
  x = y;
  y = t - (a / b) * y;
  return d;
}

函数返回值为gcd。x, y为全局变量,运行结束后均已完成修改。

原方程的解有无数个,有的解会爆long long,而扩展欧几里得算法给出的解必有\(|x|<=b\), \(|y|<=a\)

posted @ 2025-07-09 11:47  Alkaid16  阅读(19)  评论(0)    收藏  举报