同余2:线性逆元和中国剩余定理的学习笔记

同余2:逆元和中国剩余定理的学习笔记


前言
上一次,我讲到了求解线性同余方程,并挖了一个线性求逆元的大坑,现在补上吧。

逆元

逆元的定义:若 a ∗ x ≡ 1 ( m o d b ) a * x\equiv 1 \pmod b ax1(modb),且 a a a b b b互质,(若不互质则不存在),则称 x x x a a a b b b意义下的逆元,记作 a − 1 a^{-1} a1
逆元的求法:
单个:拓展欧几里得,上一篇已经讲过了。
批量:线性逆元。
假设求模 p p p的逆元。
具体如下:首先, 1 − 1 ≡ 1 ( m o d p ) 1^{-1} \equiv 1 \pmod p 111(modp)
然后,我们设 p = k ∗ i + r p = k * i + r p=ki+r,其中 k , i , r k,i,r k,i,r均为整数,且 r &lt; k r &lt; k r<k,其实 k = ⌊ p i ⌋ k = \lfloor { p \over i}\rfloor k=ip,而 r = p % i r = p \% i r=p%i
不难得到 p ≡ 0 ( m o d p ) p \equiv 0 \pmod p p0(modp),拆开得 k ∗ i + r ≡ 0 ( m o d p ) k * i + r \equiv 0 \pmod p ki+r0(modp),两边乘以 i − 1 ∗ r − 1 i^{-1}*r^{-1} i1r1得(在模 p p p意义下相等是成立的): k ∗ r − 1 + i − 1 ≡ 0 ( m o d p ) k * r^{-1} + i^{-1} \equiv 0 \pmod p kr1+i10(modp)得, i − 1 ≡ − k ∗ r − 1 ( m o d p ) i^{-1} \equiv -k * r^{-1} \pmod p i1kr1(modp)也就是 i − 1 ≡ − ⌊ p i ⌋ ∗ ( p % i ) − 1 ( m o d p ) i^{-1} \equiv - \lfloor { p \over i}\rfloor * ( p \% i)^{-1} \pmod p i1ip(p%i)1(modp)

不难得出代码:

inv[i] = -(p/i) * inv[p%i];

非常简洁, O ( n ) O(n) O(n)的时间可得出答案。

求逆元还有用费马小定理的方法,但本蒟蒻不会 ,就不赘述了。

中国剩余定理

中国剩余定理是用来求线性同余方程组的解的,出自《孙子算经》中的题目:今有物不知其数,三三数之剩二(模3得2),五五数之剩三(模5得3),七七数之剩二(模7得2),问物几何?这个问题就是孙子问题,也就是中国剩余定理的由来了。
古人的口诀为:三人同行七十稀,五树梅花廿一支,七子团圆正半月,除百零五便得知。
翻译过来为:
第一步,找出5和7的公倍数中模3得1的最小数为70,找出3和7的公倍数中模5得3的最小数为21,找出3和5的公倍数中模7得1的最小数为15;
第二步,用70乘以2,21乘以3,15乘以2,得出和为233,不难发现,这个数模3得2,模5得3,模7得2;
第三步,算出3,5,7三个数的最小公倍数为105,将233除以105,得到余数为23,这个即为符合要求的最小正整数。
原问题用严谨的数学语言表述就是:
{ x ≡ 2 ( m o d 3 ) x ≡ 3 ( m o d 5 ) x ≡ 2 ( m o d 7 ) \begin{cases} x \equiv 2 \pmod {3} \\[1ex] x \equiv 3 \pmod {5} \\[1ex] x \equiv 2 \pmod {7} \end{cases} x2(mod3)x3(mod5)x2(mod7)
通过上述方法的第一步,古人提示我们先考虑以下三个同余方程:
{ x ≡ 1 ( m o d 3 ) x ≡ 0 ( m o d 5 ) (1) x ≡ 0 ( m o d 7 ) \begin{cases} x \equiv 1 \pmod {3} \\[1ex] x \equiv 0 \pmod {5} &amp; &amp; &amp; \text{(1)} \\[1ex] x \equiv 0 \pmod {7} \end{cases} x1(mod3)x0(mod5)x0(mod7)(1)
{ x ≡ 0 ( m o d 3 ) x ≡ 1 ( m o d 5 ) (2) x ≡ 0 ( m o d 7 ) \begin{cases} x \equiv 0 \pmod {3} \\[1ex] x \equiv 1 \pmod {5}&amp;&amp;&amp; \text{(2)} \\[1ex] x \equiv 0 \pmod {7} \end{cases} x0(mod3)x1(mod5)x0(mod7)(2)
{ x ≡ 0 ( m o d 3 ) x ≡ 0 ( m o d 5 ) (3) x ≡ 1 ( m o d 7 ) \begin{cases} x \equiv 0 \pmod {3} \\[1ex] x \equiv 0 \pmod {5}&amp;&amp;&amp; \text{(3)} \\[1ex] x \equiv 1 \pmod {7} \end{cases} x0(mod3)x0(mod5)x1(mod7)(3)
以第一个方程为研究对象,通过观察,不难发现第一组线性同余方程的解一定为5,7的公倍数,可写出一个公式为 35 ∗ x ≡ 1 ( m o d 3 ) 35*x \equiv 1 \pmod 3 35x1(mod3),这个公式用拓展欧几里得可求出最小正整数解为70,那么,求出它又有什么用呢?
此时,我们不妨设 1 0 = 70 0 \begin{matrix} &amp; 1 \\ &amp; 0 &amp; = &amp; 70 \\ &amp; 0 \\ \end{matrix} 100=70
即表示第一个同余方程组的解,
0 1 = 21 0 \begin{matrix} &amp; 0 \\ &amp; 1 &amp; = &amp; 21 \\ &amp; 0 \\ \end{matrix} 010=21
表示第二个同余方程组的解,
0 0 = 15 1 \begin{matrix} &amp; 0 \\ &amp; 0 &amp; = &amp; 15 \\ &amp; 1 \\ \end{matrix} 001=15
表示第三个同余方程组的解。
2 3 2 \begin{matrix} &amp; 2 \\ &amp; 3 \\ &amp; 2 \\ \end{matrix} 232表示原方程组的解
不难得出这些奇怪的数列相加得出的解满足条件,在取模的情况下,两个数相加时,它们之间的余数和若不大于取模用的数,则它们的和的余数为原先两个数的余数和,即 a % p + b % p = ( a + b ) % p a \% p + b \% p =(a + b) \% p a%p+b%p=(a+b)%p
最后得出以下式子:
2 1 0 0 3 = 2 ∗ 0 + 3 ∗ 1 + 2 ∗ 0 = 2 ∗ 70 + 3 ∗ 21 + 2 ∗ 15 ≡ 23 ( m o d 105 ) 2 0 0 1 \begin{matrix} &amp; 2 &amp; &amp; &amp; &amp; 1&amp; &amp;&amp;&amp;0&amp;&amp;&amp;&amp;0\\ &amp; 3 &amp; = &amp; 2 &amp; * &amp; 0 &amp; + &amp; 3 &amp; * &amp; 1&amp;+&amp;2&amp;*&amp;0 &amp; = 2 * 70 + 3 * 21 + 2 * 15 \equiv23 \pmod {105} \\ &amp; 2&amp; &amp; &amp; &amp; 0 &amp;&amp;&amp;&amp;0&amp;&amp;&amp;&amp;1\\ \end{matrix} 232=2100+3010+2001=270+321+21523(mod105)
将答案取模它们的最大公因数后,余数关系仍成立。
我们好像发现了什么,那就让我们从特殊推广到一般吧。
中国剩余定理的基本内容是(摘自《数学一本通》):设自然数 m 1 , m 2 , . . . , m r m_1,m_2,...,m_r m1,m2,...,mr两两互素,并记 N = m 1 ∗ m 2 ∗ . . . ∗ m r N = m_1*m_2*...*m_r N=m1m2...mr,则同余方程组:

{ x ≡ b 1 ( m o d m 1 ) x ≡ b 2 ( m o d m 2 ) . . . . . . x ≡ b r ( m o d m r ) \begin{cases} x \equiv b_1\pmod {m_1} \\[1ex] x \equiv b_2\pmod {m_2} \\[1ex] ...\\[1ex] ...\\[1ex] x \equiv b_r\pmod {m_r} \end{cases} xb1(modm1)xb2(modm2)......xbr(modmr)在模 N N N同余的意义下有唯一解。
根据上述方法,考虑同余方程组
{ x ≡ 0 ( m o d m 1 ) . . . x ≡ 0 ( m o d m i − 1 ) x ≡ 1 ( m o d m i ) x ≡ 0 ( m o d m i + 1 ) . . . x ≡ 0 ( m o d m r ) \begin{cases} x \equiv 0 \pmod {m_1} \\[1ex] ...\\[1ex] x \equiv 0 \pmod {m_{i - 1}} \\[1ex] x \equiv 1 \pmod {m_i} \\[1ex] x \equiv 0 \pmod {m_{i + 1}} \\[1ex] ...\\[1ex] x \equiv 0 \pmod {m_r} \end{cases} x0(modm1)...x0(modmi1)x1(modmi)x0(modmi+1)...x0(modmr)
其中 1 ≤ i ≤ r 1 \le i \le r 1ir
由于这些数两两互素,令 x i = ( N m i ) x_i = ({N \over m_i} ) xi=(miN),因为所有m互素,保证求出的答案不会增大其它 m m m的余数,推出同余方程为 k i ∗ x i ≡ 1 ( m o d m i ) k_i*x_i \equiv 1 \pmod {m_i} kixi1(modmi),最终解为 b i ∗ k i ∗ x i b_i * k_i * x_i bikixi。将所有解加上并注意对 N N N取模即可。
板子
[TJOI2009]猜数字 https://www.luogu.org/problem/P3868
本题等同于求解 { x ≡ a 1 ( m o d b 1 ) x ≡ a 2 ( m o d b 2 ) . . . . . . x ≡ a k ( m o d b k ) \begin{cases} x \equiv a_1\pmod {b_1} \\[1ex] x \equiv a_2\pmod {b_2} \\[1ex] ...\\[1ex] ...\\[1ex] x \equiv a_k\pmod {b_k} \end{cases} xa1(modb1)xa2(modb2)......xak(modbk)
注意a可能为负,以及数据过大要用"快(gui)速乘"。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
#define N 13
using namespace std;
ll a[N] , b[N] , k , n;
inline void read( ll & res ) {
	res = 0;
	ll pd = 1;
	char aa = getchar();
	while ( aa < '0' || aa > '9' ) {
		if ( aa == '-' ) {
			pd = -pd;
		}
		aa = getchar();
	}
	while ( aa >= '0' && aa <= '9' ) {
		res = ( res << 1 ) + ( res << 3 ) + ( aa - '0' );
		aa = getchar();
	}
	res *= pd;
	return;
}
inline ll mul( ll tem , ll t ) {
	ll ans = 0;
	while ( t ) {
		if ( t & 1 ) {
			ans = ( ans + tem ) % n;
		}
		tem = ( tem + tem ) % n;
		t >>= 1;
	}
	return ans;
}
inline 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 tem = x;
	x = y;
	y = tem - a / b * y;
	return d;
}
inline ll china(){
	ll res = 0;
	for ( int i = 1 ; i <= k ; ++i ) {
		ll x , y;
		exgcd( n / b[i] , b[i] , x , y );
		res = ( res + mul( mul( x , n/b[i] ) % n , a[i] ) % n ) % n;
	}
	return( res % n + n ) % n;
}
int main () {
	n = 1;
	read(k);
	for ( int i = 1 ; i <= k ; ++i ) {
		read(a[i]);
	}
	for ( int i = 1 ; i <= k ; ++i ) {
		read(b[i]);
		n *= b[i];
		a[i] = ( a[i] % b[i] + b[i] ) % b[i];
	}
	printf("%lld",china());
	return 0;
}

扩展中国剩余定理

求解:
{ x ≡ b 1 ( m o d m 1 ) x ≡ b 2 ( m o d m 2 ) . . . . . . x ≡ b r ( m o d m r ) \begin{cases} x \equiv b_1\pmod {m_1} \\[1ex] x \equiv b_2\pmod {m_2} \\[1ex] ...\\[1ex] ...\\[1ex] x \equiv b_r\pmod {m_r} \end{cases} xb1(modm1)xb2(modm2)......xbr(modmr)
问题和上面差不多,不过自然数 m 1 , m 2 , . . . , m r m_1,m_2,...,m_r m1,m2,...,mr不再两两互素
这样上面的方法就不适用了,第一步的做法不能保证对一个数进行操作时,不会增大取模其它数的余数。
对于这一点我们考虑使用类似数学归纳法的做法,具体来说,共分为两点:
一,定义初始状态;
二,思考如何从当前状态转到下一个状态。
好吧,不玩深沉了,所谓定义初始状态,就是直接得出第一组的解,第一组的解就是 b 1 b_1 b1
所谓从当前状态转到下一个状态,就是合并思想,将当前这一组的解与前面所有组的解建立联系;不过为了方便,我们先考虑合并其中两个组,设为: { x ≡ b i ( m o d m i ) x ≡ b j ( m o d m j ) \begin{cases} x \equiv b_i\pmod {m_i} \\[1ex] x \equiv b_j\pmod {m_j} \\[1ex] \end{cases} xbi(modmi)xbj(modmj)不难看出上式可表示为: { x = m i ∗ k i + b i x = m j ∗ k j + b j \begin{cases} x = m_i * k_i + b_i \\[1ex] x = m_j * k_j + b_j \\[1ex] \end{cases} x=miki+bix=mjkj+bj
所以 m i ∗ k i − m j ∗ k j = b j − b i m_i * k_i - m_j * k_j = b_j -b_i mikimjkj=bjbi
a = m i a = m_i a=mi b = m j b = m_j b=mj c = b j − b i c = b_j -b_i c=bjbi
用扩欧求解同余方程 a ∗ x ′ ≡ c ( m o d b ) a * x&#x27; \equiv c \pmod {b} axc(modb)
不难得出 k i k_i ki的一种解,即为 x ′ ∗ c G C D ( a , b ) x&#x27; *{ c \over GCD(a,b)} xGCDa,bc
如果 c % G C D ( a , b ) ! = 0 c \% GCD(a,b) != 0 c%GCDa,b!=0
那么整个方程组无解。
z = m j G C D ( m i , m j ) z = {m_j \over GCD(m_i,m_j)} z=GCD(mi,mj)mj,将得出的 k i k_i ki经过计算 ( k i % z + z ) % z (k_i \%z+z)\%z (ki%z+z)%z即可得到最小正整数解。
则两个公式的通解为 x = m i ∗ k i + b i x = m_i * k_i + b_i x=miki+bi,它可以对 L C M ( m i , m j ) LCM(m_i,m_j) LCM(mi,mj)取模,不影响余数的大小。
如果是合并当前组与所有在当前组的前面的组, { x ≡ N ( m o d M ) x ≡ b i ( m o d m i ) \begin{cases} x \equiv N \pmod {M} \\[1ex] x \equiv b_i\pmod {m_i} \\[1ex] \end{cases} xN(modM)xbi(modmi)其中 N N N表示前 i − 1 i - 1 i1组的解,M表示为 L C M ( m 1 , m 2 , . . . , m i − 1 ) LCM(m_1 , m_2 , ... , m_{i - 1}) LCM(m1,m2,...,mi1)
N N N已经保存了所有前 i − 1 i - 1 i1个的取余条件,所有满足 x ≡ N ( m o d M ) x \equiv N \pmod {M} xN(modM)的数都能成为前 i − 1 i - 1 i1个方程的解。此时,只要再满足第 i i i个方程,就可以得出前 i i i个方程的通解。
得出:
{ x = M ∗ k 1 + N x = m i ∗ k 2 + b i \begin{cases} x = M * k_1 + N \\[1ex] x = m_i * k_2 + b_i \\[1ex] \end{cases} x=Mk1+Nx=mik2+bi
所以 M ∗ k 1 − m i ∗ k 2 = b i − N M * k_1 - m_i * k_2 = b_i -N Mk1mik2=biN
按照上面合并两个同余方程的方法,用扩欧不难得出答案。
按照这种方法,从1一直递推到 r r r,就可以得出结果。
板子
【模板】扩展中国剩余定理(EXCRT)https://www.luogu.org/problem/P4777
就是一道模板题,不过注意要用“快(gui)速乘”。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
ll aa[N] , bb[N];
ll n;
inline void read( ll & res ) {
	res = 0;
	ll pd = 1;
	char a = getchar();
	while ( a < '0' || a > '9' ) {
		if ( a == '-' ) {
			pd = -pd;
		}
		a = getchar();
	}
	while ( a >= '0' && a <= '9' ) {
		res = ( res << 1 ) + ( res << 3 ) + ( a - '0' );
		a = getchar();
	}
	res *= pd;
	return;
}
inline ll mul( ll a , ll b , ll mod ) {
	ll ans = 0;
	while ( b ) {
		if ( b & 1 ) {
			ans = ( ans + a ) % mod;
		}
		a = ( a + a ) % mod;
		b >>= 1;
	}
	return ans;
}
inline 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 t = x;
	x = y;
	y = t - a / b * y;
	return d;
}
inline ll china() {
	ll ans = bb[1];
	ll m = aa[1];
	for ( int i = 2 ; i <= n ; ++i ) {
		ll a = m;
		ll b = aa[i];
		ll c = ( bb[i] - ans % b + b ) % b;//式子在模b后仍成立,这里是为了保证c是正整数 
		ll x , y;
		ll d = exgcd( a , b , x , y );
		if ( c % d != 0 ) {
			return -1;
		}
		ll tem = b/d;
		ll res = mul( x , c/d , tem );
		ans += res * m;
		m *= tem;
		ans = ( ans % m + m ) % m;
	}
	return ( ans % m + m ) % m;
}
int main () {
	read(n);
	for ( int i = 1 ; i <= n ; ++i ) {
		read(aa[i]);
		read(bb[i]);
	}
	printf("%lld",china());
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值