当前位置:网站首页>扩展中国剩余定理

扩展中国剩余定理

2022-08-10 20:54:00 aWty_

exCRT

CRT

  关于 C R T CRT CRT,主要的思想是这样的,对于一个方程组:

{ x ≡ a 1 ( m o d m 1 ) x ≡ a 1 ( m o d m 2 ) ⋮ x ≡ a n ( m o d m n ) \begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_1 \pmod {m_2} \\ \vdots \\ x \equiv a_n \pmod {m_n} \end{cases} xa1(modm1)xa1(modm2)xan(modmn)

  来说我们令:

m = ∏ i = 1 n m i , M i = m m i m = \prod_{i = 1}^n m_i, M_i = \frac m {m_i} m=i=1nmi,Mi=mim

  然后求出 M i M_i Mi 在模 m i m_i mi 意义下的乘法逆元 t i t_i ti,于是我们就得到了答案:

a n s = ∑ i = 1 n a i M i t i ans = \sum_{i = 1}^n a_i M_i t_i ans=i=1naiMiti

  在这里的计算步骤中,显然在计算逆元的时候要求 gcd ⁡ ( M i , m i ) = 1 \gcd(M_i, m_i) = 1 gcd(Mi,mi)=1,那么也就是要求 { m i } \{ m_i \} { mi} l两两互质。

exCRT

总体思路

  扩展中国剩余定理就是要解决 m i m_i mi 两两不互质的情况时解方程的方法。

  但是我们稍微经过一些思考就能发现,要想在 C R T CRT CRT 的基础上小改一下来实现 e x C R T exCRT exCRT 时不可能的,因为如果 gcd ⁡ ( M i , m i ) ≠ 1 \gcd(M_i, m_i) \neq 1 gcd(Mi,mi)=1 的话那么连逆元都不存在了,所以我们需要跳出 C R T CRT CRT 的框架来思考怎样进行扩展。

  我们考虑合并两个方程,如果可以做到很快的合并,那么我们只需要一直合并下去再直接求解剩下的,唯一一个的,简单的,显然的,线性同余方程就能解决问题了。

合并

  考虑两个方程的合并:

{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) \begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_2 \pmod {m_2} \end{cases} { xa1(modm1)xa2(modm2)

  那么根据同余的性质我们就能得到:

x = k 1 m 1 + a 1 = k 2 m 2 + a 2 x = k_1m_1 + a_1 = k_2 m_2 + a_2 x=k1m1+a1=k2m2+a2

  移一下项:

k 1 m 1 − k 2 m 2 = a 2 − a 1 k_1m_1 - k_2m_2 = a_2 - a_1 k1m1k2m2=a2a1

  这个式子的形式可能没有那么直观,所以我们令 a = m 1 , b = m 2 , c = a 2 − a 1 , x = k 1 , y = − k 2 a = m_1, b = m_2, c = a_2 - a_1, x = k_1, y = -k_2 a=m1,b=m2,c=a2a1,x=k1,y=k2,这个式子是不是就瞬间变成了这样:

a x + b y = c ax + by = c ax+by=c

  这就是一个经典的不定方程求解的问题了,那么根据裴蜀定理,我们就能知道:

  1. 如果 gcd ⁡ ( m 1 , m 2 ) ∣ ( r 2 − r 1 ) \gcd(m_1, m_2) \mid (r_2 - r_1) gcd(m1,m2)(r2r1),那么方程可以直接用 e x g c d exgcd exgcd 求出她的一组特殊解
  2. 否则,方程无解

  那么我们求出 x = k 1 m 1 + a 1 x = k_1m_1 + a_1 x=k1m1+a1 之后就得到了一个 x x x 的特殊解同时满足这两个方程。我们给这个特殊解一个新的变量名 X X X

  于是我们就可以愉快的构造新的方程了:

x ≡ X ( m o d l c m ( m 1 , m 2 ) ) x \equiv X \pmod {lcm(m_1, m_2)} xX(modlcm(m1,m2))

  这个构造应该是非常显然的,因为 x x x X X X m 1 m_1 m1 同余且 x x x X X X m 2 m_2 m2 同余,那么 x x x X X X l c m ( m 1 , m 2 ) lcm(m_1, m_2) lcm(m1,m2) 同余。

算法流程总结

  1. 在所有方程中取两个出来
  2. 合并(如果不能合并输出无解)
  3. 只剩下一个方程直接解这唯一的一个方程得到答案

  完结撒花!!!

代码

#include<bits/stdc++.h>
using namespace std;
#define int __int128
#define in read()
#define MAXN 100100

inline int read(){
    
	int x = 0; char c = getchar();
	while(c < '0' or c > '9') c = getchar();
	while('0' <= c and c <= '9'){
    
		x = x * 10 + c - '0'; c = getchar();
	}
	return x;
}
void write(int x){
    
	if(x < 0) putchar('-'), x = -x;
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

int n = 0;
int a[MAXN] = {
     0 };
int m[MAXN] = {
     0 };

int k1 = 0, k2 = 0;
int exgcd(int a, int b, int &x, int &y){
    
	if(!b) {
     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;
}

signed main(){
    
	n = in; int ans = 0, lcm = 0;
	for(int i = 1; i <= n; i++) m[i] = in, a[i] = in;
	for(int i = 1; i < n; i++){
    
		k1 = 0, k2 = 0;
		int d = exgcd(m[i], m[i + 1], k1, k2);
		if((a[i + 1] - a[i]) % d != 0) {
     puts("-1"); return 0; }
		lcm = m[i] / d * m[i + 1];
		a[i + 1] = k1 * (a[i + 1] - a[i]) / d * m[i] + a[i];
		a[i + 1] = (a[i + 1] % lcm + lcm) % lcm; m[i + 1] = lcm;
	}
	int y = 0;
	exgcd(1, m[n], ans, y);
	write((ans * a[n] + m[n]) % m[n]);
	return 0;
}
原网站

版权声明
本文为[aWty_]所创,转载请带上原文链接,感谢
https://blog.csdn.net/ID246783/article/details/126262569