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^jhash[val]=j;}a=power(a,t,p); //a^tif(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;
}