• 扩展中国剩余定理


    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 )

    {xa1(modm1)xa1(modm2)xan(modmn)" role="presentation" style="position: relative;">{xa1(modm1)xa1(modm2)xan(modmn)
    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 )

    {xa1(modm1)xa2(modm2)" role="presentation" style="position: relative;">{xa1(modm1)xa2(modm2)
    {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
    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] - a[i]) 再除以 d
    		// 因为有可能 k1 很小,先除以 d 就可能变成 0 然后再乘也没用了
    		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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 相关阅读:
    【无标题】
    一台电脑如何登录多个抖音小店(抖音小店怎么关联多个账号)
    在Vue中通过ElementUI构建前端页面【登录,注册】,在IEDA构建后端实现前后端分离
    FreeRTOS学习day1
    机器人内部传感器阅读梳理及心得-速度传感器-数字式速度传感器
    解决卸载node升级到node12版本后踩坑sass-loader和node-sass版本冲突的问题
    LeetCode234. 回文链表(day0025_1)
    7.idea 使用 docker 构建 spring boot 项目
    计算机网络-应用层(文件传输协议(FTP协议),电子邮件系统(SMTP协议,MIME,POP3,IMAP协议))
    Area Listener 区域监听器
  • 原文地址:https://blog.csdn.net/ID246783/article/details/126262569