这是一个数论系列:)
一、素数
×费马小定理
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 来代替,这就是逆元的用途。