0x33
同余
定义
若整数 a a a和整数 b b b除以正整数 m m m的余数相等,则称 a , b a,b a,b模 m m m同余,记为 a ≡ b ( m o d m ) a\equiv b(mod\ m) a≡b(mod m)。
同余类与剩余类
对于 ∀ a ∈ [ 0 , m − 1 ] \forall a\in[0,m-1] ∀a∈[0,m−1],集合 { a + k m } ( k ∈ Z ) \{a+km\}(k\in Z) {a+km}(k∈Z)的所有数模 m m m同余,余数都是 a a a。该集合称为一个模 m m m的同余类,简记为 a ‾ \overline{a} a。
模 m m m的同余类一共有 m m m个,分别为 0 ‾ , 1 ‾ , 2 ‾ , . . . , m − 1 ‾ \overline0,\overline1,\overline2,...,\overline{m-1} 0,1,2,...,m−1。它们构成 m m m的完全剩余类。
1 ∼ m 1\sim m 1∼m中与 m m m互质的数代表的同余类共有 ϕ ( m ) \phi(m) ϕ(m)个,它们构成 m m m的简化剩余类。例如,模10的简化剩余类为 { 1 ‾ , 3 ‾ , 7 ‾ , 9 ‾ } \{\overline1,\overline3,\overline7,\overline9 \} {1,3,7,9}。
简化剩余关系关于模 m m m乘法封闭。这是因为若 a , b ( 1 ≤ a , b ≤ m ) a,b(1\leq a,b \leq m) a,b(1≤a,b≤m)与 m m m互质,则 a ∗ b a*b a∗b也不可能与 m m m含有相同的因子,即 a ∗ b a*b a∗b也与 m m m互质。再由余数的定义即可得到 a ∗ b m o d m a*b\bmod m a∗bmodm也与 m m m互质,即 a ∗ b m o d m a*b\bmod m a∗bmodm也属于 m m m的简化剩余类。
费马小定理
若 p p p是质数,则对于任意整数 a a a,有 a p ≡ a ( m o d p ) a^p\equiv a(\bmod p) ap≡a(modp)。
欧拉定理
若正整数 a , n a,n a,n互质,则 a ϕ ( n ) ≡ 1 ( m o d n ) a^{\phi(n)}\equiv 1(\bmod n) aϕ(n)≡1(modn),其中 ϕ ( n ) \phi(n) ϕ(n)为欧拉函数。
证明:
设
n
n
n的简化剩余类为
a
1
‾
,
a
2
‾
,
.
.
.
,
a
ϕ
(
n
)
‾
{\overline{a_1},\overline{a_2},...,\overline{a_{\phi(n)}}}
a1,a2,...,aϕ(n)。对于
∀
a
i
,
a
j
\forall a_i,a_j
∀ai,aj,若
a
∗
a
i
≡
a
∗
a
j
(
m
o
d
n
)
a*a_i\equiv a*a_j(\bmod n)
a∗ai≡a∗aj(modn),则
a
∗
(
a
i
−
a
j
)
≡
0
a*(a_i-a_j)\equiv 0
a∗(ai−aj)≡0。因为
a
,
n
a,n
a,n互质,所以
a
i
−
a
j
≡
0
a_i-a_j\equiv 0
ai−aj≡0,即当
a
i
≡
a
j
a_i\equiv a_j
ai≡aj。故当
a
i
≠
a
j
a_i\neq a_j
ai=aj时,
a
a
i
,
a
a
j
aa_i,aa_j
aai,aaj也代表不同的同余类。
又因为简化剩余系关于模
n
n
n乘法封闭,故
a
a
i
‾
\overline{aa_i}
aai也在简化剩余系集合中。因此,集合
{
a
1
‾
,
a
2
‾
,
.
.
.
,
a
ϕ
(
n
)
‾
}
\{\overline{a_1},\overline{a_2},...,\overline{a_{\phi(n)}} \}
{a1,a2,...,aϕ(n)}与集合
{
a
a
1
‾
,
a
a
2
‾
,
.
.
.
,
a
a
ϕ
(
n
)
‾
}
\{\overline{aa_1},\overline{aa_2},...,\overline{aa_{\phi(n)}} \}
{aa1,aa2,...,aaϕ(n)}都能表示
n
n
n的简化剩余类。综上所述:
a
ϕ
(
n
)
a
1
a
2
.
.
.
a
ϕ
(
n
)
≡
(
a
a
1
)
(
a
a
2
)
.
.
.
(
a
a
ϕ
(
n
)
)
≡
a
1
a
2
.
.
.
a
ϕ
(
n
)
(
m
o
d
n
)
a^{\phi(n)}a_1a_2...a_{\phi(n)}\equiv (aa_1)(aa_2)...(aa_{\phi(n)})\equiv a_1a_2...a_{\phi(n)}(\bmod n)
aϕ(n)a1a2...aϕ(n)≡(aa1)(aa2)...(aaϕ(n))≡a1a2...aϕ(n)(modn)
因此
a
ϕ
(
n
)
≡
1
(
m
o
d
n
)
a^{\phi(n)}\equiv 1(\bmod n)
aϕ(n)≡1(modn)。
当 p p p是质数时, ϕ ( p ) = p − 1 \phi(p)=p-1 ϕ(p)=p−1,并且只有 p p p的倍数与 p p p不互质。所以,只要 a a a不是 p p p的倍数,就有 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv 1(\bmod p) ap−1≡1(modp),两边同乘 a a a就是费马小定理。另外,若 a a a是 p p p的倍数,费马小定理显然成立(取模之后结果为0)。
欧拉定理的推论
设正整数 a , n a,n a,n互质,则对于任意正整数 b b b,有 a b ≡ a b m o d ϕ ( n ) ( m o d n ) a^b\equiv a^{b\bmod \phi(n)}(\bmod n) ab≡abmodϕ(n)(modn)。
证明:
设
b
=
q
∗
ϕ
(
n
)
+
r
b=q*\phi(n)+r
b=q∗ϕ(n)+r,其中
0
≤
r
≤
ϕ
(
n
)
0\leq r\leq \phi(n)
0≤r≤ϕ(n),即
r
=
b
m
o
d
ϕ
(
n
)
r=b\bmod \phi(n)
r=bmodϕ(n)。于是:
a
b
≡
a
q
∗
ϕ
(
n
)
+
r
≡
(
a
ϕ
(
n
)
)
q
∗
a
r
≡
a
r
≡
a
b
m
o
d
ϕ
(
n
)
(
m
o
d
n
)
a^b\equiv a^{q*\phi(n)+r}\equiv(a^{\phi(n)})^q*a^r\equiv a^r\equiv a^{b\bmod \phi(n)}(\bmod n)
ab≡aq∗ϕ(n)+r≡(aϕ(n))q∗ar≡ar≡abmodϕ(n)(modn)
许多计数类的题目要求我们把答案对一个质数
p
p
p取模后输出。面对
a
+
b
,
a
−
b
,
a
∗
b
a+b,a-b,a*b
a+b,a−b,a∗b这样的算式,可以在计算前先把
a
,
b
a,b
a,b对
p
p
p取模。面对乘方算式,根据欧拉定理的推论,可以先把底数对
p
p
p取模、指数对
ϕ
(
p
)
\phi(p)
ϕ(p)取模,再计算乘方。
特别地,当 a , n a,n a,n不一定互质且 b > ϕ ( n ) b>\phi(n) b>ϕ(n)时,有 a b ≡ a b m o d ϕ ( n ) + ϕ ( n ) ( m o d n ) a^b\equiv a^{b\bmod \phi(n)+\phi(n)}(\bmod n) ab≡abmodϕ(n)+ϕ(n)(modn)。这意味着即使底数与模数不互质,我们也有办法把指数地规模缩小到容易计算地范围内。上式可以通过寻找 a b m o d n a^b \bmod n abmodn的指数循环节证明,可以自行思考。
1.扩展欧几里得算法
B e ˊ z o u t Bézout Beˊzout定理
对于任意整数 a , b a,b a,b,存在一对整数 x , y x,y x,y,满足 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)。
证明:
在欧几里得算法的最后一步,即 b = 0 b=0 b=0时,显然有一对整数 x = 1 , y = 0 x=1,y=0 x=1,y=0,使得 a ∗ 1 + b ∗ 0 = g c d ( a , 0 ) a*1+b*0=gcd(a,0) a∗1+b∗0=gcd(a,0)。
若 b > 0 b>0 b>0,则 g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a,b)=gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)。假设存在一对整数 x , y x,y x,y,满足 b ∗ x + ( a m o d b ) ∗ y = g c d ( b , a m o d b ) b*x+(a\bmod b)*y=gcd(b,a\bmod b) b∗x+(amodb)∗y=gcd(b,amodb),因为 b x + ( a m o d b ) y = b x + ( a − b ⌊ a / b ⌋ ) y = a y + b ( x − ⌊ a / b ⌋ y ) bx+(a\bmod b)y=bx+(a-b\lfloor a/b \rfloor)y=ay+b(x-\lfloor a/b\rfloor y) bx+(amodb)y=bx+(a−b⌊a/b⌋)y=ay+b(x−⌊a/b⌋y),所以令 x ′ = y , y ′ = x − ⌊ a / b ⌋ y x^{\prime}=y, y^{\prime}=x-\lfloor a / b\rfloor y x′=y,y′=x−⌊a/b⌋y,就得到了 a x ′ + b y ′ = g c d ( a , b ) ax^{\prime}+by^{\prime}=gcd(a,b) ax′+by′=gcd(a,b)。
对于欧几里得算法的递归过程中应用数学归纳法,可知 B e ˊ z o u t Bézout Beˊzout定理成立。
B e ˊ z o u t Bézout Beˊzout定理是按照欧几里得算法的思路证明的,且上述证明方法同时给出了整数 x x x和 y y y的计算方法。这种计算方法称为扩展欧几里得算法。
int exgcd(int a,int b,int &x,int &y)
{
if(b==0){x=1,y=0;return a;}
int d=exgcd(b,a%b,x,y);
int z=x;x=y;y=z-y*(a/b);
return d;
}
定义变量 d , x 0 , y 0 d,x_0,y_0 d,x0,y0,调用 d = e x g c d ( a , b , x 0 , y 0 ) d=exgcd(a,b,x0,y0) d=exgcd(a,b,x0,y0)。注意在上述代码中, x 0 , y 0 x_0,y_0 x0,y0是以引用的方式传递的。上述程序求出方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的一组特解 x 0 , y 0 x_0,y_0 x0,y0,并返回 a , b a,b a,b的最大公约数 d d d。
对于更为一般的方程 a x + b y = c ax+by=c ax+by=c,它有解当且仅当 d ∣ c d\mid c d∣c。我们可以先求出 a x + b y = d ax+by=d ax+by=d的一组特解 x 0 , y 0 x_0,y_0 x0,y0,然后令 x 0 , y 0 x_0,y_0 x0,y0同时乘上 c / d c/d c/d,就得到了 a x + b y = c ax+by=c ax+by=c的一组特解 ( c / d ) x 0 , ( c / d ) y 0 (c/d)x_0,(c/d)y_0 (c/d)x0,(c/d)y0。
事实上,方程
a
x
+
b
y
=
c
ax+by=c
ax+by=c的通解可以表示为:
x
=
c
d
x
0
+
k
b
d
,
y
=
c
d
y
0
−
k
a
d
(
k
∈
Z
)
x=\frac{c}{d}x_0+k\frac{b}{d},y=\frac{c}{d}y_0-k\frac{a}{d}(k\in Z)
x=dcx0+kdb,y=dcy0−kda(k∈Z)
其中
k
k
k取遍整数集合,
d
=
g
c
d
(
a
,
b
)
,
x
0
,
y
0
d=gcd(a,b),x_0,y_0
d=gcd(a,b),x0,y0是
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)的一组特解。
乘法逆元
若整数 b , m b,m b,m互质,并且 b ∣ a b\mid a b∣a,则存在一个整数 x x x,使得 a / b ≡ a ∗ x ( m o d m ) a/b\equiv a*x(\bmod m) a/b≡a∗x(modm)。称 x x x为 b b b的模 m m m乘法逆元,记为 b − 1 ( m o d m ) b^{-1}(\bmod m) b−1(modm)。
因为 a / b ≡ a ∗ b − 1 ≡ a / b ∗ b ∗ b − 1 ( m o d m ) a/b\equiv a*b^{-1}\equiv a/b*b*b^{-1}(\bmod m) a/b≡a∗b−1≡a/b∗b∗b−1(modm),所以 b ∗ b − 1 ≡ 1 ( m o d m ) b*b^{-1}\equiv 1(\bmod m) b∗b−1≡1(modm)。
如果 m m m是质数(此时我们用符号 p p p代替 m m m),并且 b < p b<p b<p,根据费马小定理, b p − 1 ≡ 1 ( m o d p ) b^{p-1}\equiv 1(\bmod p) bp−1≡1(modp),即 b ∗ b p − 2 ≡ 1 ( m o d p ) b*b^{p-2}\equiv 1(\bmod p) b∗bp−2≡1(modp)。因此,当模数 p p p为质数时, b p − 2 b^{p-2} bp−2即为 b b b的乘法逆元。
如果只是保证 b , m b,m b,m互质,那么乘法逆元可通过求解同余方程 b ∗ x ≡ 1 ( m o d m ) b*x\equiv 1(\bmod m) b∗x≡1(modm)得到。下个部分我们就来介绍线性同余方程及其求解方法。
有了乘法逆元,我们在计数类问题中即使遇到 a / b a/b a/b这样的除法算式,也可以先把 a , b a,b a,b各自对模数 p p p取模,再计算 a ∗ b − 1 m o d p a*b^{-1}\bmod p a∗b−1modp作为最终的结果。当然,前提必须保证 b , p b,p b,p互质(当 p p p是质数时,等价于 b b b不是 p p p的倍数)。
到目前为止,我们在模 p p p运算下对加、减、乘、除、乘方运算都已经有了适当的处理方式。
2.线性同余方程
给定整数 a , b , m a,b,m a,b,m,求一个整数 x x x满足 a ∗ x ≡ b ( m o d m ) a*x\equiv b(\bmod m) a∗x≡b(modm),或者给出无解。因为未知数的指数为1,所以我们称之为一次同余方程,也称为线性同余方程。
a ∗ x ≡ b ( m o d m ) a*x\equiv b(\bmod m) a∗x≡b(modm)等价于 a ∗ x − b a*x-b a∗x−b是 m m m的倍数,不妨设为 − y -y −y倍。于是,该方程可以改写为 a ∗ x + m ∗ y = b a*x+m*y=b a∗x+m∗y=b。
根据 B e ˊ z o u t Bézout Beˊzout定理及其证明过程,线性同余方程有解当且仅当 g c d ( a , m ) ∣ b gcd(a,m)\mid b gcd(a,m)∣b。
在有解时,先用欧几里得算法求出一组整数 x 0 , y 0 x_0,y_0 x0,y0,满足 a ∗ x 0 + m ∗ y 0 = g c d ( a , m ) a*x_0+m*y_0=gcd(a,m) a∗x0+m∗y0=gcd(a,m)。然后 x = x 0 ∗ b / g c d ( a , m ) x=x_0*b/gcd(a,m) x=x0∗b/gcd(a,m)就是原线性同余方程的一个解。
方程的通解则是所有模 m / g c d ( a , m ) m/gcd(a,m) m/gcd(a,m)与 x x x同余的整数。
由上述线性同余方程的知识可得, a ∗ x ≡ 1 ( m o d b ) a*x\equiv 1(\bmod b) a∗x≡1(modb)有解当且仅当 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1。方程可以改写为 a ∗ x + b ∗ y = 1 a*x+b*y=1 a∗x+b∗y=1,用欧几里得算法求出一组特解 x 0 , y 0 x_0,y_0 x0,y0,则 x 0 x_0 x0就是原方程的一个解,通解为所有模 b b b与 x 0 x_0 x0同余的整数。通过取模操作把解的范围移动到 1 ∼ b 1\sim b 1∼b之间,就得到了最小正整数。
typedef long long ll;
ll a,b,x,y;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b){x=1,y=0;return a;}
ll d=exgcd(b,a%b,x,y);
ll z=x;x=y;y=z-y*(a/b);
return d;
}
int main()
{
cin>>a>>b;
exgcd(a,b,x,y);
cout<<(x%b+b)%b<<endl; //注意通过同余方程求出的解可能为负数记得要加上一个b
}
中国剩余定理
设
m
1
,
m
2
,
.
.
.
,
m
n
m_1,m_2,...,m_n
m1,m2,...,mn是两两互质的整数,
m
=
∏
i
=
1
n
m
i
,
M
i
=
m
/
m
i
,
t
i
m=\prod_{i=1}^{n}m_i,M_i=m/m_i,t_i
m=∏i=1nmi,Mi=m/mi,ti是线性同余方程
M
i
t
i
≡
1
(
m
o
d
m
i
)
M_it_i\equiv 1(\bmod m_i)
Miti≡1(modmi)的一个解。对于任意的
n
n
n个整数
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an,方程组
{
x
≡
a
1
(
m
o
d
m
1
)
x
≡
a
2
(
m
o
d
m
2
)
⋮
x
≡
a
n
(
m
o
d
m
n
)
\left\{\begin{array}{c} x \equiv a_{1}\left(\bmod m_{1}\right) \\ x \equiv a_{2}\left(\bmod m_{2}\right) \\ \vdots \\ x \equiv a_{n}\left(\bmod m_{n}\right) \end{array}\right.
⎩
⎨
⎧x≡a1(modm1)x≡a2(modm2)⋮x≡an(modmn)
有整数解,解为
x
=
∑
i
=
1
n
a
i
M
i
t
i
x=\sum_{i=1}^n a_iM_it_i
x=∑i=1naiMiti。
证明:
因为
M
i
=
m
/
m
i
M_i=m/m_i
Mi=m/mi是除
m
i
m_i
mi之外所有模数的倍数,所以
∀
k
≠
i
,
a
i
M
i
t
i
≡
0
(
m
o
d
m
k
)
\forall k\neq i,a_iM_it_i\equiv 0(\bmod m_k)
∀k=i,aiMiti≡0(modmk)。又因为
a
i
M
i
t
i
≡
a
i
(
m
o
d
m
i
)
a_iM_it_i\equiv a_i(\bmod m_i)
aiMiti≡ai(modmi),所以代入
x
=
∑
i
=
1
n
a
i
M
i
t
i
x=\sum_{i=1}^n a_iM_it_i
x=∑i=1naiMiti,原方程组成立。
另外,即使模数不满足两两互质,我们也有方法判断线性同余方程组是否有解,并求出方程组的解。可以考虑使用数学归纳法,假设已经求出了前 k − 1 k-1 k−1个方程构成的方程组的一个解 x x x。记 m = l c m ( m 1 , m 2 , . . . , m k − 1 ) m=lcm(m_1,m_2,...,m_{k-1}) m=lcm(m1,m2,...,mk−1),则 x + i ∗ m ( i ∈ Z ) x+i*m(i\in Z) x+i∗m(i∈Z)是前 k − 1 k-1 k−1个方程的通解。
考虑第 k k k个方程,求出一个整数 t t t,使得 x + t ∗ m ≡ a k ( m o d m k ) x+t*m\equiv a_k(\bmod m_k) x+t∗m≡ak(modmk)。该方程等价于 m ∗ t ≡ a k − x ( m o d m k ) m*t\equiv a_k-x(\bmod m_k) m∗t≡ak−x(modmk),其中 t t t是未知量。这就是一个线性同余方程,可以用扩展欧几里得算法判断是否有解,并求出它的解。若有解,则 x ′ = x + t ∗ m x^{\prime}=x+t*m x′=x+t∗m就是前 k k k个方程构成的方程组的一个解。
综上所述,我们使用了 n n n次扩展欧几里得算法,就求出了整个方程组的解。
3.高次同余方程
关于高次同余方程,有 a x ≡ b ( m o d p ) a^x\equiv b(\bmod p) ax≡b(modp)和 x a ≡ b ( m o d p ) x^a\equiv b(\bmod p) xa≡b(modp)两类问题。不过后者超出了我们的讨论范围,可以自行查阅“原根”“阶”“指标”的相关资料。我们重点来解决前者。
问题:给定整数 a , b , p a,b,p a,b,p,其中 a , p a,p a,p互质,求一个非负整数 x x x,使得 a x ≡ b ( m o d p ) a^x\equiv b(\bmod p) ax≡b(modp)。
Baby Step,Gaint Step
算法
因为 a , p a,p a,p互质,所以可以在模 p p p意义下执行关于 a a a的乘、除法运算。
设 x = i ∗ t − j x=i*t-j x=i∗t−j,其中 t = ⌈ p ⌉ , 0 ≤ j ≤ t − 1 t=\lceil \sqrt{p} \rceil,0\leq j\leq t-1 t=⌈p⌉,0≤j≤t−1,则方程变为 a i ∗ t − j ≡ b ( m o d p ) a^{i*t-j}\equiv b(\bmod p) ai∗t−j≡b(modp)。即 ( a t ) i ≡ b ∗ a j ( m o d p ) (a^t)^i\equiv b*a^j(\bmod p) (at)i≡b∗aj(modp)。
对于所有的
j
∈
[
0
,
t
−
1
]
j\in[0,t-1]
j∈[0,t−1],把
b
∗
a
j
m
o
d
p
b*a^j\bmod p
b∗ajmodp插入一个Hash
表。
枚举
i
i
i的所有可能取值,即
i
∈
[
0
,
t
]
i\in[0,t]
i∈[0,t],计算出
(
a
t
)
i
m
o
d
p
(a^t)^i\bmod p
(at)imodp,在Hash
表中查找是否存在对应的
j
j
j,更新答案即可。时间复杂度
O
(
p
)
O(\sqrt{p})
O(p)。
下面的程序实现了Baby Step,Gaint Step
算法,计算同余方程
a
x
≡
b
(
m
o
d
p
)
a^x\equiv b(\bmod p)
ax≡b(modp)的最小非负整数解,无解时返回-1。
int baby_step_giant_step(int a,int b,int p)
{
map<int,int> hash;hash.clear();
b%=p;
int t=(int)sqrt(p)+1;
for(int j=0;j<t;++j)
{
int val=(long long)b*power(a,j,p)%p; //b*a^j
hash[val]=j;
}
a=power(a,t,p); //a^t
if(a==0) return b==0?1:-1;
for(int i=0;i<=t;++i)
{
int val=power(a,i,p); //(a^t)^i;
int j= hash.find(val)==hash.end()?-1:hash[val];
if(j>=0&&i*t-j>=0) return i*t-j;
}
return -1;
}