• 扩展中国剩余定理详解


    前言

    阅读本文前,推荐先学一下中国剩余定理。其实不学也无所谓,毕竟两者没啥关系

    扩展CRT

    我们知道,中国剩余定理是用来解同余方程组

    $$egin{cases}xequiv c_{1}left( mod m_{1} ight) \ xequiv c_{2}left( mod m_{2} ight) \ ldots \ xequiv c_rleft( mod m_r ight) end{cases}$$

    但是有一个非常令人不爽的事情就是它要求$m_1,m_2ldots,m_r$两两互素

    如果某个毒瘤出题人偏要求它们部互素呢?

    其实也有解决的办法

    就是把出题人吊起来干一顿用扩展中国剩余定理

    扩展中国剩余定理跟中国剩余定理没半毛钱关系,一个是用扩展欧几里得,一个是用构造

    首先我们还是从简单入手,考虑一下如果同余方程组只有两个式子的情况

    $xequiv c_{1}left( mod m_{1} ight) \ xequiv c_{2}left( mod m_{2} ight)$

    将两个式子变形

    $x=c_{1}+m_{1}k_{1}\ x=c_{2}+m_{2}k_{2}$

    联立

    $c_{1}+m_{1}k_{1}=c_{2}+m_{2}k_{2}$

    移项

    $m_{1}k_{1}=c_{2}-c_{1}+m_{2}k_{2}$

    我们用$(a,b)$表示$a,b$的最大公约数

    在这里需要注意,这个方程有解的条件是

    $left( m_{1},m_{2} ight) |left( c_{2}-c_{1} ight)$,因为后面会用到$dfrac {left( c_{2}-c_{1} ight) }{left( m_{2},m_{1} ight) }$这一项,如果不整除的话肯定会出现小数。

    对于上面的方程,两边同除$(m_1,m_2)$

    $$dfrac {m_{1}k_{1}}{left( m_{1},m_{2} ight) }=dfrac {c_{2}-c_{1}}{left( m_{1},m_{2} ight) }+dfrac {m_{2}k_{2}}{left( m_{1},m_{2} ight) }$$

    $$dfrac {m_{1}}{left( m_{1},m_{2} ight) }k_{1}=dfrac {c_{2}-c_{1}}{left( m_{1},m_{2} ight) }+dfrac {m_{2}}{left( m_{1},m_{2} ight) }k_{2}$$

    转换一下

    $$dfrac {m_{1}}{left( m_{1},m_{2} ight) }k_{1} equiv dfrac {c_{2}-c_{1}}{left( m_{1},m_{2} ight) } (mod dfrac {m_{2}}{left( m_{1},m_{2} ight) })$$

    此时我们已经成功把$k_2$消去了。

    同余式两边同除$dfrac {m_{1}}{left( m_{1},m_{2} ight) }$

    $$k_1equiv inv({m_1over(m_1,m_2)},{m_2over (m_1,m_2)})*{(c_2-c_1)over (m_1,m_2)}pmod {{m_2over(m_1,m_2)}}$$

    $inv(a,b)$表示$a$在模$b$意义下的逆元

    $$k_1=inv({m_1over(m_1,m_2)},{m_2over (m_1,m_2)})*{(c_2-c_1)over (m_1,m_2)}+{{m_2over (m_1,m_2)}}*y$$

    接下来怎么办呢?这个式子已经化到最简了。。

    不要忘了,我们刚开始还有两个式子。我们把$k_1$待回去!

    $$x=inv({m_1over(m_1,m_2)},{m_2over (m_1,m_2)})*{(c_2-c_1)over (m_1,m_2)}*m_1+y{{m_1m_2over (m_1,m_2)}}+c_1$$

    $$xequiv inv({m_1over(m_1,m_2)},{m_2over (m_1,m_2)})*{(c_2-c_1)over (m_1,m_2)}*m_1+c_1pmod {{m_1m_2over (m_1,m_2)}}$$

    此时,整个式子中的元素我们都已经知道了

    具体一点,这个式子可以看做是$$xequiv cpmod m$$

    其中$$c=(inv({m_1over (m_1,m_2)},{m_2over (m_1,m_2)})*{(c_2-c_1)over (m_1,m_2)})\%{m_2over (m_1,m_2)}*m_1+c_1$$

    $$m={m_1m_2over (m_1,m_2)}$$

    推广一下

    我们每次把两个同余式合并,求解之后得到一个新的同余式。再把新的同余式和其他的联立,最终就可以求出满足条件的解

    代码

    update in 2018.10.11:这份代码可能在较强的数据下出现乘爆long long的情况(我记得NOI2018Day2T1就是因为这个过不了大样例)

    直接把#define LL long long 改成#define LL __int128就好了

    题目链接

    #include<iostream>
    #include<cstdio>
    #define LL long long
    using namespace std;
    const LL MAXN = 1e6 + 10;
    LL K, C[MAXN], M[MAXN], x, y;
    LL gcd(LL a, LL b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    LL exgcd(LL a, LL b, LL &x, LL &y) {
        if (b == 0) {x = 1, y = 0; return a;}
        LL r = exgcd(b, a % b, x, y), tmp;
        tmp = x; x = y; y = tmp - (a / b) * y;
        return r;
    }
    LL inv(LL a, LL b) {
        LL r = exgcd(a, b, x, y);
        while (x < 0) x += b;
        return x;
    }
    int main() {
    #ifdef WIN32
        freopen("a.in", "r", stdin);
    #else
    #endif
        while (~scanf("%lld", &K)) {
            for (LL i = 1; i <= K; i++) scanf("%lld%lld", &M[i], &C[i]);
            bool flag = 1;
            for (LL i = 2; i <= K; i++) {
                LL M1 = M[i - 1], M2 = M[i], C2 = C[i], C1 = C[i - 1], T = gcd(M1, M2);
                if ((C2 - C1) % T != 0) {flag = 0; break;}
                M[i] = (M1 * M2) / T;
                C[i] = ( inv( M1 / T , M2 / T ) * (C2 - C1) / T ) % (M2 / T) * M1 + C1;
                C[i] = (C[i] % M[i] + M[i]) % M[i];
            }
            printf("%lld
    ", flag ? C[K] : -1);
        }
        return 0;
    }

    再放道裸题

    http://acm.hdu.edu.cn/showproblem.php?pid=1573

    题解

  • 相关阅读:
    如何了解网络链路的性能,吞吐量测试
    Struts+Spring+HibernateSSH整合实例
    在百度贴吧打出被和谐的字和特殊字符:比如繁体字
    SVN 小记
    SVN 小记
    SVN needslock 设置强制只读属性
    在百度贴吧打出被和谐的字和特殊字符:比如繁体字
    TortoiseSVN与Subversion 1.5
    .NET中非对称加密RSA算法的密钥保存
    SVN needslock 设置强制只读属性
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8425731.html
Copyright © 2020-2023  润新知