数论(一)——素数,GCD,LCM

来源:互联网 发布:精子检查中优化处理 编辑:程序博客网 时间:2024/05/17 22:04

这是一个数论系列:)


一、素数


×费马小定理

Theorem: 设 p 是一个素数,a 是一个整数且不是 p 的倍数,那么

很遗憾,费马小定理的逆定理是不成立的。对 a = 2,满足的非素数 n 是存在的。

比如 n = 341 = 11 × 31

对于整数 a,称满足的合数为以 a 为底的伪素数。

经测试,
前 10 亿的自然数中,同时以 2 和 3 为底的伪素数有 1272 个。
我们用费马小定理验证素数的话,出错的概率大概只有 0.000025。


×Miller-Rabin

Theorem:.若 p 是素数,x 是一个正整数,且  那么

Corollary:设待测数为 n,取一个比 n 小的正整数 a,设,若 n 是素数,则要么,要么存在一个 i,满足 0 ≤ i < r 且 

Solution:随机选取 k 个小于待测整数 n 的正整数作为底 a,用上面那个推论的逆定理来测试。时间复杂度O(k log n)。

这种方法仍是有反例的,但是若选择 2 和 3 为底,第一个反例就大到了 1373653。

Example:给出一个正整数n, 求不超过n的所有素数。

Solution:

1.枚举1-n的所有数做素数测试, 时间复杂度是O(n log n)。

2.逐次枚举 2 到 n,设当前枚举到 x,那么对所有满足标记为非素数。时间复杂度 O(n log n)。

3.线性筛法:

memset(not_prime, 0, sizeof(not_prime));not_prime[1] = true;for (int i = 2; i <= n; ++i){    if (!not_prime[i]) prime[++ prime_count] = i;    for (int j = 1; j <= prime_count; ++j)    {        if (prime[j] * i > n) break;        not_prime[prime[j] * i] = true;        if (i % prime[j] == 0) break;    }}

关键在倒数第3行,它保证了我们总是能够找到每个数的最小的那个素因子。因为每个不小于1 的整数的最小素因子个数是 1,所以复杂度是 O(n)。

×唯一分解定理

Theorem:每个大于1的整数均可分解为有限个素数的乘积, 并且若不计因子在分解中的次序, 则这种分解式是唯一的。


二、GCD 和 LCM


×Definition(GCD,LCM):略。

×Example: 给两个正整数a, b, 求他们的最大公约数和最小公倍数。

×Solution:欧几里得算法

int Gcd(int a, int b) {    if (b == 0) return a;    else return Gcd(b, a % b);}
求 n 个不超过 m 的正整数的最大公约数的复杂度是 O(n + log m)。

×Example: 求不定方程 ax + by = m 的整数解。

×Theorem:ax+ by = m 有整数解当且仅当 (a, b)|m。

×Theorem:设 (x0 , y0 ) 是不定方程 ax + by = m 的一组解, (a, b) = g,那么全部解为,其中t为所有整数。

×Solution(扩展欧几里得算法)

int ExGcd(int a, int b, int &x, int &y) {    if (b == 0)     {        x = 1, y = 0;        return a;    }    else     {        int g = ExGcd(b, a % b, x, y);        int t = x;        x = y, y = t - a / b * x;        return g;    }}

考虑从 bx + (a mod b)y = g 的 (x, y) 推导到 ax′ + by′ = g 的 (x′ , y′ )。

以NOIp2012提高组Day2Mod一题为例子:

#include <cstdio>#include <cstring>#include <cstdlib>using namespace std;int exgcd(int a, int b, int &x, int &y){if (b == 0){x = 1, y = 0;return a;}else{int g = exgcd(b, a % b, x, y);int t = x;x = y, y = t - a / b * x;return g;}}int main(){int a, b, x, y, d;scanf("%d%d", &a, &b);d = exgcd(a, b, x, y);if (d == 1) printf("%d\n", (x % b + b) % b);return 0;}

×Example:求解一次同余方程组

                                                          

×Solution:当mi两两互素时, 是经典的中国剩余定理, 请自行百度或Google。

×Solution:介绍一种基于“合并”思想的算法, 当mi不满足两两互素时, 也同样能够工作

可以写成

设 g = gcd(m1, m2), 若b2 - b1 能被g整除,则可以继续

用扩展欧几里得算法算出,则两个同余式可以合并为


×Definition(逆元):设正整数模m, 对于任意正整数a满足(a, m) = 1, 总存在惟一的b满足 且 , 称b为模m意义下a的逆元。其实,严格意义上讲b属于模m的一个缩系。

×Example:给出正整数a 和 m,保证 (a, m) = 1,求模 m 意义下 a 的逆元。

×Solution:根据定义用扩展欧几里得解一个线性同余方程即可

注意到 a × b ≡ 1 (mod m) 可以认为是 ,所以当我们需要在模 m意义下除以 a 时,可以用乘上 b 来代替,这就是逆元的用途。

原创粉丝点击