GCD(辗转相除法)
最大公约数
求两个数a和b的最大公约数,考虑一般情况,设a > b
约定符号|, A ∣ B A\;|\;B A∣B表示A是B的约数
这里,假如一个数d,满足 d ∣ a d\;|\;a d∣a , 并且 d ∣ b d \;|\; b d∣b ,(即:d为a与b的共同的约数
则 d ∣ ( x × a + y × b ) d\;|(x \times a + y \times b) d∣(x×a+y×b) ,(x,y为任意整数) ,
把a拆开,a可以表示为 a = k × b + r a = k \times b + r a=k×b+r (这里的 r为 a m o d b a \mod b amodb, 即a除以b得到的余数)
$ k = \lfloor \frac{a}{b} \rfloor , 0 \leq r < b$
带入得 $r = a - \lfloor \frac{b}{a} \rfloor \times b $
满足前面 x × a + y × b x \times a + y \times b x×a+y×b的形式,所以 d ∣ r d \; | \; r d∣r,即 d ∣ ( a m o d b ) d \;| \;(a \mod b) d∣(amodb)
即,可以证明,任意d,即a与b任意的约数都同时是 a m o d b a \mod b amodb 的约数,
所以求a和b的最大公约数可以转化为求b与 a m o d b a \mod b amodb的最大公约数
约定0和任意正整数的最大公约数为那个正整数本身,即
g c d ( a , 0 ) = a gcd(a, 0 ) = a gcd(a,0)=a
裴蜀定理(贝祖定理)
扩展欧几里得定理(exgcd)
定义 :设a,b是不全为0的整数,则存在整数x,y,使得 a x + b y = g c d ( a , b ) ax+by = gcd(a,b) ax+by=gcd(a,b)
(类比刚才的gcd的求法)
存在, a x + b y = g c d ( a , b ) ax+by = gcd(a,b) ax+by=gcd(a,b) ——(1)
也存在 b x 1 + ( a m o d b ) y 1 = g c d ( a , b ) bx_1 + (a \mod b) y_1 = gcd(a, b) bx1+(amodb)y1=gcd(a,b) (因为这里的 g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a,b) = gcd(b, a\mod b) gcd(a,b)=gcd(b,amodb))——(2)
(1)和(2)的等式右边都是 g c d ( a , b ) gcd(a,b) gcd(a,b),所以可以连等(
尝试把后面这个式子展开
可以得到
b
x
1
+
(
a
m
o
d
b
)
y
1
=
b
x
1
+
(
a
−
⌊
a
b
⌋
×
b
)
y
1
=
b
x
1
+
a
y
1
−
⌊
a
b
⌋
×
b
y
1
=
a
y
1
+
b
(
x
1
−
⌊
a
b
⌋
×
y
1
)
bx_1 + (a \mod b) y _1 \\ = bx_1 + (a - \lfloor \frac{a}{b} \rfloor \times b) y_1 \\ = bx_1 + ay_1 -\lfloor \frac{a}{b} \rfloor \times by_1 \\ = ay_1 + b(x_1 - \lfloor \frac{a}{b} \rfloor \times y_1)
bx1+(amodb)y1=bx1+(a−⌊ba⌋×b)y1=bx1+ay1−⌊ba⌋×by1=ay1+b(x1−⌊ba⌋×y1)
观察(1)式,得到这里的
{
x
=
y
1
y
=
x
1
−
⌊
a
b
⌋
×
y
1
\begin{cases} x = y_1 \\ y = x_1 - \lfloor \frac{a}{b} \rfloor \times y_1 \end{cases}
{x=y1y=x1−⌊ba⌋×y1
可以注意到求
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by = gcd(a,b)
ax+by=gcd(a,b)的x,y和求
b
x
1
+
(
a
m
o
d
b
)
y
1
=
g
c
d
(
a
,
b
)
bx_1 + (a \mod b) y_1 = gcd(a, b)
bx1+(amodb)y1=gcd(a,b) 的
x
1
,
y
1
x_1,y_1
x1,y1是可以互相转化的
而将前一个问题((1)式的问题)转化为后一个问题((2)式的问题) 可以将问题规模变小:
因为这里的 a > b a > b a>b, b > a m o d b b > a \mod b b>amodb)
可以证明他们是趋向于0的,
我们来考虑一下当 b = 0 b = 0 b=0时候这个问题的解,
a × x + 0 × y = g c d ( a , 0 ) = a a \times x+ 0 \times y = gcd(a,0) = a a×x+0×y=gcd(a,0)=a,
因为证明存在,我们可以任意取一组,比如
{
x
=
1
y
=
0
\begin{cases} x = 1 \\ y = 0 \end{cases}
{x=1y=0
将它倒推回去,就可以得到原问题的解
费马小定理
定义 : 若p
为素数,gcd(a,p) = 1
,则
a
p
−
1
≡
1
(
m
o
d
p
)
a^{p - 1} \equiv 1(\mod p)
ap−1≡1(modp)
应用 : 降幂 : a b ≡ a b m o d ( p − 1 ) ( m o d p ) a ^ b \equiv a^{b \mod (p - 1)} (\mod p) ab≡abmod(p−1)(modp)
逆元
定义 : 如果一个线性同余方程
a
x
≡
1
(
m
o
d
p
)
ax \equiv 1 (\mod p)
ax≡1(modp) ,则x
称为a mod p
的逆元,记作
a
−
1
a^{-1}
a−1
求法 :
- sol1 扩展欧几里得
a x ≡ 1 ( m o d p ) ax \equiv 1 (\mod p) ax≡1(modp)
可以转化为 a × x = 1 + p × t a \times x = 1 + p \times t a×x=1+p×t ( t ∈ Z t \in Z t∈Z)的形式
a,p互质,可以转化为求 a × x + p × y = 1 a\times x\;+\;p \times y = 1 a×x+p×y=1
- sol2 快速幂法
a x ≡ 1 ( m o d p ) ax \equiv 1(\mod p) ax≡1(modp) , 求x,费马 a p − 1 ≡ 1 ( m o d p ) a^{p - 1} \equiv 1(\mod \; p) ap−1≡1(modp)
a x ≡ a p − 1 ( m o d p ) ax \equiv a^{p - 1}(\mod p) ax≡ap−1(modp)
x ≡ a p − 2 ( m o d p ) x \equiv a ^{p - 2}(\mod p) x≡ap−2(modp)
再用快速幂
- sol3 线性求逆元 (公式 不要求掌握
n次计算算出1到n所有数对于p的逆元,复杂度是线性的
1 − 1 ≡ 1 ( m o d p ) 1^{-1} \equiv 1(\mod p) 1−1≡1(modp)
把p拆开:
设
p
=
k
×
i
+
j
p = k \times i + j
p=k×i+j,
j
<
i
,
1
<
i
<
p
j < i, 1 <i < p
j<i,1<i<p, 再放到mod p
意义下 (这里i是1到 p-1 任意的整数)
先不要管为什么这样拆,先看下去)
k × i + j ≡ 0 ( m o d p ) k \times i + j \equiv 0 (\mod p) k×i+j≡0(modp)
两边同时乘上 i − 1 , j − 1 i^{-1}, j^{-1} i−1,j−1
得到 k j − 1 + i − 1 ≡ 0 ( m o d p ) k j^{-1} + i ^ {-1} \equiv 0 (\mod p) kj−1+i−1≡0(modp)
i − 1 ≡ − k j − 1 ( m o d p ) i ^ {-1} \equiv -k j^{-1} (\mod p) i−1≡−kj−1(modp) 代入 p = k × i + j p = k \times i + j p=k×i+j
i − 1 ≡ − ( ⌊ p i ⌋ ) ( p m o d i ) − 1 ( m o d p ) i ^{- 1} \equiv - (\lfloor \frac{p}{i} \rfloor)(p \mod i)^{-1} (\mod p) i−1≡−(⌊ip⌋)(pmodi)−1(modp)
代码
将i
对于p的逆元记作inv[i]
,
− ( ⌊ p i ⌋ ) ≡ ( p − ( ⌊ p i ⌋ ) ) ( m o d p ) -(\lfloor \frac{p}{i} \rfloor) \equiv (p - (\lfloor \frac{p}{i} \rfloor)) (\mod p) −(⌊ip⌋)≡(p−(⌊ip⌋))(modp) 在取模的意义下是一样的,是将负数变成正数
inv[1] = 1;
for (int i = 2; i <= n; ++i)
inv[i] = (long long)(p - p / i) * inv[p % i] % p;
因为 j (即 p m o d i p \mod i pmodi)小于 i,我们这里又是按顺序求每个 i 的逆元,在求i的逆元用到 j 的时候,可以保证一定求过 j