数论初步
一、唯一分解定理
基本描述
任何一个大于1的自然数N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积.
理解
换句话说,它来指导我们分解质因数。
想想在分解质因数的时候,我们使用的是短除法,先试除2,然后试除3,其实就是用到的唯一分解定理。
代码
找出num的所有质因数
void findfactor(int num){
v.clear();
int i = 2;
while(num != 1){
if(num % i == 0){
v.push_back(i);
while(num % i==0) num/=i;
}
++i;
}
}
二、欧几里得算法
基本描述
当我们需要算出两个数字的最大公约数,就要用到欧几里得算法。
这个算法不需要过多介绍了。
代码
int gcd(int a, int b){
if(!b) return a; else return gcd(b,a%b);
}
拓展
那么最小公倍数呢?
lcm(a,b) = a * b/gcd(a,b)
但是要注意,在a,b很大的时候,即使使用的是long long,a*b是有溢出的风险的,
所以最好写成:
lcm(a,b) = a/gcd(a,b) * b
即先除再乘,防止溢出。
三、素数筛法
Eratosthenes 筛法
首先在[1,nmax]筛掉2的所有倍数,然后从筛掉3的倍数,再筛掉4的倍数……,一直到sqrt(nmax+0.5)。
但是会发现,有些数字被筛了两次,如8在筛2倍数的时候筛掉一次,筛4倍数的时候筛掉一次,这样效率会大大低下。
解决方案就是,在选择被筛倍数的数字的时候,先判断一下是否被筛掉,若没被筛掉再继续。
代码
void prime(){
memset(isprime,1,sizeof isprime);
for(int i = 2;i<=(int)(sqrt(nmax+0.5));++i){
if(isprime[i])
for(int j = 2;i*j<nmax;++j)
isprime[i*j] = false;
}
}
欧拉线性筛
对于处理素数,还有更高效的线性筛法,在学习了欧拉函数之后,再来讲解。
素数定理
π(x) = x/lnx
四、拓展欧几里得
基本描述
找出一对整数(a,b),使得ax+by = gcd(a,b),其中x,y不一定是正数,也有可能是负数或零。那么如何实现呢?
代码实现
void exgcd(ll a, ll b, ll& d, ll& x, ll &y){
if(!b){
d = a,x = 1,y = 0;
}else{
exgcd(b, a % b, d, y, x);
y -= x * (a / b);
}
}
拓展
按照如上的代码,就可以求得一组可行解(x1,x2)。
如果需要求解其他解,如何实现呢?
我们可以做到的是,求出另外一组可行解(x2,y2),并且可以得出以下等式
ax1 + by1 = ax2 + by2, 他们都等于gcd(a,b).
通过简单的变形,可以进一步得到a(x1-x2) = b(y2-y2),并且假设gcd(a,b) = g
方程式两边同时除以g,可以得到(a/g) * (x1-x2) = (b/g) * (y2-y1).
令 a’ = a/g, b’ = b/g, 不难得到a’与b’是互质的,进一步得到
a’(x1-x2) = b’(y2-y1) ,由于a’与b’互质,所以(x1-x2) 一定是b’的整数倍,令(x1-x2)/b’ = k, 从而得到
y2-y1 = ka’ ,进而得出以下结论
结论1
若已经求解出ax+by = c的一组整数解为(x0,y0),则其任意解都可以写成(x0+kb’,yo-ka’)的形式,其中,a’ = a/gcd(a,b),b’ = b/gcd(a,b),k为任意整数。
结论2
对于方程ax+by = c来说:
设a,b,c为任意整数,g = gcd(a,b),方程ax+by = g的一组解是(x0,y0),则当c是g的倍数的时候,ax+by = c的一组解是(x0 * c / g , y0 * c / g).若c不是g的倍数的时候无整数解。
举例
- 求解6x+15y=9,根据欧几里得算法,得到一组解为(-2,1),满足-2 * 6 + 1 * 15 = 3,由于9是3的倍数,将系数成3即可,即 -6 * 6 + 3 * 15 = 9.
- 求解6x+15y=8, 8不是3的倍数,无整数解。
五、模运算
基本描述
当计算的结果非常大时,题目经常要求输出对某一个素数取模后的结果,在计算的过程当中就涉及到,如何进行模运算。模运算可分为,加法模,减法模,乘法模和乘方模。
公式
加法模
(a+b) mod n = ((a mod n) + (b mod n)) mod n
减法模
(a - b) mod n = ((a mod n) - (b mod n) + mod) mod n
乘法模
ab mod n = (a mod n) (b mod n) mod n
乘方模
乘方模看做是多次对乘法模的运算即可
六、快速幂
基本描述
(之前写过一篇ppt,就直接拿来用了)
实现代码
(同时对m取模)
int ans = 1;
while(n){
if(n&1) ans = ans * base % m;
n >>= 1;
base = ((base%m)*(base%m))%m;
}
七、同余与模线性方程
基本描述
先来看看韩信点兵的故事:
韩信带1500名兵士打仗,战死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韩信很快说出人数:1049。
设总人数为a,可以得出:
a ≡ 2(mod 3)
a ≡ 4(mod 5)
a ≡ 6(mod 7)
其中≡的意思是同余,即a mod 3 = 2 mod 3, a mod 5 = 4 mod 5, a mod 7 = 6 mod 7.
同余定理
定理1
如果a ≡ b (mod m), 则 m|(a-b),其中|表示整除。
例如: 73 ≡ 23 (mod 10), 则有 10 | (73 - 23).
定理2
如果 a ≡ b (mod m), c ≡ b (mod m), 则 a ± c ≡ b ± d (mod m)
例如 73 ≡ 3 (mod 10), 84 ≡ 4 (mod 10) , 则有 73 ± 84 ≡ 3 ± 4 (mod 10)
定理3
如果 a ≡ b (mod m), c ≡ b (mod m), 则 a × c ≡ b × d (mod m)
例如 73 ≡ 3 (mod 10), 84 ≡ 4 (mod 10) , 则有 73 × 84 ≡ 3 × 4 (mod 10)
定理4
如果 a ≡ b (mod m), a^n ≡ b^n (mod m)
例如 40 ≡ 1 (mod 13), 则有 40^2 ≡ 1^2 (mod 13)