中国剩余定理和扩展中国剩余定理——杨子曰数学

中国剩余定理——杨子曰数学

超链接:数学合集


问:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?


换成人话(这才不是人话好吗):

解方程:
{ x ≡ a 1 ( m o d   m 1 ) x ≡ a 2 ( m o d   m 2 ) x ≡ a 3 ( m o d   m 3 ) ⋮ x ≡ a n ( m o d   m n ) \left\{ \begin{aligned} x & \equiv a_1(mod\ m_1)\\ x & \equiv a_2(mod\ m_2)\\ x & \equiv a_3(mod\ m_3)\\ \vdots\\ x & \equiv a_n(mod\ m_n)\\ \end{aligned} \right. xxxxa1(mod m1)a2(mod m2)a3(mod m3)an(mod mn) ( m 1 , m 2 , m 3 ⋯ ⋯ m n 互 质 , I t ′   v e r y   i m p o r t a n t ) (m_1,m_2,m_3 \cdots \cdots m_n互质,It'\ very \ important) (m1,m2,m3mnIt very important)


中国剩余定理

我们先来讲肿么做,再来讲为啥可以这样做

How to do?

  1. 求出 m i m_i mi的lcm
    比如文章最上面的那道题,我们先求出 m = l c m ( 3 , 5 , 7 ) = 105 m=lcm(3,5,7)=105 m=lcm(3,5,7)=105
  2. M i = m m i M_i=\frac{m}{m_i} Mi=mim
    于是,我们有了: M 1 = 105 / 3 = 35 , M 2 = 105 / 5 = 21 , M 3 = 105 / 7 = 15 M_1=105/3=35,M_2=105/5=21,M_3=105/7=15 M1=105/3=35M2=105/5=21,M3=105/7=15
  3. 让M_i扩大一定的倍数s,使得 s ∗ M i   m o d   m i = a i s*M_i\ mod\ m_i=a_i sMi mod mi=ai
    在这个例子中: M 1   m o d   m 1 = 35   m o d   3 = 2 M_1\ mod\ m_1=35\ mod\ 3=2 M1 mod m1=35 mod 3=2
    欧,发现不用扩大就已经满足了 M 1   m o d   m 1 = a 1 M_1\ mod\ m_1=a_1 M1 mod m1=a1
    继续, M 2   m o d   m 2 = 21   m o d   5 = 1 M_2\ mod\ m_2=21\ mod\ 5=1 M2 mod m2=21 mod 5=1
    余数需要变成3,那我们就把被除数变成原来的3倍
    也就是 63   m o d   5 = 3 63\ mod\ 5=3 63 mod 5=3
    然后, M 3   m o d   m 3 = 15   m o d   7 = 1 M_3\ mod\ m_3=15\ mod\ 7=1 M3 mod m3=15 mod 7=1
    余数得是2,那我们就要把 M 3 M_3 M3变为2倍
    也就是: 30   m o d   7 = 2 30\ mod\ 7=2 30 mod 7=2
  4. 把扩大后的 m i m_i mi全部加起来,我们就得到了答案:
    a n s = M 1 + M 2 + M 3 = 35 + 63 + 30 = 128 ans=M_1+M_2+M_3=35+63+30=128 ans=M1+M2+M3=35+63+30=128
  5. 如果你喜欢的话把 a n s   m o d   m ( 它 们 的 l c m ) ans\ mod\ m(它们的lcm) ans mod m(lcm),使答案落在0~m之间
    a n s = a n s   m o d   m = 128   m o d   105 = 23 ans=ans\ mod\ m=128\ mod\ 105=23 ans=ans mod m=128 mod 105=23
    OK,完事

Why这样做我们可以找到答案?

其实 M i M_i Mi就是除了 m i m_i mi以外的其他所有 m i m_i mi的lcm(←别忘了它们是两两互质的)
也就是说M_i扩大了任意被模其他 m i m_i mi都是不受影响的

那我们就可以随便扩大,让 M i   m o d   m i = a i M_i\ mod \ m_i=a_i Mi mod mi=ai不就好了吗?
至于如何让 M i M_i Mi变成我们想要的值,其实我们先要算的是 M i M_i Mi在模 m i m_i mi下的逆元(逆元,什么?戳),也就是我们想让 k ∗ M i   m o d   m i = 1 k*M_i\ mod\ m_i=1 kMi mod mi=1,这是再把 k ∗ M i k*M_i kMi扩大相应的倍数,就行了

OK,完事

int china()
{
    int ans=0,lcm=1,x,y;
    for(int i=1;i<=n;i++) lcm*=m[i];
    for(int i=1;i<=n;i++)
    {
        int M=lcm/m[i];
        ex_gcd(M,m[i],x,y);
        x=(x%m[i]+m[i])%m[i];
        ans=(ans+M*x*a[i])%lcm;
    }
    return (ans+lcm)%lcm;
}

扩展中国剩余定理

{ x ≡ a 1 ( m o d   m 1 ) x ≡ a 2 ( m o d   m 2 ) x ≡ a 3 ( m o d   m 3 ) ⋮ x ≡ a n ( m o d   m n ) \left\{ \begin{aligned} x & \equiv a_1(mod\ m_1)\\ x & \equiv a_2(mod\ m_2)\\ x & \equiv a_3(mod\ m_3)\\ \vdots\\ x & \equiv a_n(mod\ m_n)\\ \end{aligned} \right. xxxxa1(mod m1)a2(mod m2)a3(mod m3)an(mod mn)
一样的方程只不过这里的 m i m_i mi不互质了


它与中国剩余定理半毛钱关系也木有~~
我们先来看一看如果只有两个方程的情况:
{ x ≡ a 1 ( m o d   m 1 ) x ≡ a 2 ( m o d   m 2 ) \left\{ \begin{aligned} x & \equiv a_1(mod\ m_1)\\ x & \equiv a_2(mod\ m_2)\\ \end{aligned} \right. {xxa1(mod m1)a2(mod m2)
这个方程组其实可以转化成:
{ x = a 1 + k 1 ∗ m 1 x = a 2 + k 2 ∗ m 2 \left\{ \begin{aligned} x=a_1+k_1*m_1\\ x=a_2+k_2*m_2\\ \end{aligned} \right. {x=a1+k1m1x=a2+k2m2
然后我们把两式相减,就得到了:
k 1 ∗ m 1 − k 2 ∗ m 2 = a 2 − a 1 k_1*m_1-k_2*m_2=a_2-a_1 k1m1k2m2=a2a1
哦,有没有发现这是一个形如这个的方程: a ∗ x + b ∗ y = c a*x+b*y=c ax+by=c

也就是说我们可以用扩展欧几里得解决(那是什么?戳)

于是,我们就得到了 k 1 k_1 k1 − k 2 -k_2 k2

然后 x 0 = k 1 ∗ m 1 + a 1 x_0=k_1*m_1+a_1 x0=k1m1+a1

我们也就知道了方程的通解是: x = x 0 + m ∗ l c m ( m 1 , m 2 ) x=x_0+m*lcm(m_1,m_2) x=x0+mlcm(m1,m2)(不停扩大或减小 l c m ( m 1 , m 2 ) lcm(m_1,m_2) lcm(m1,m2)对它们的余数是没有影响的)

也就是说: x ≡ x 0 ( m o d   l c m ( m 1 , m 2 ) ) x \equiv x_0(mod\ lcm(m_1,m_2)) xx0(mod lcm(m1,m2))

有没有发现我们把两个方程合并成了 一个!!

然后不停地合并下去,我们就得到了答案!

poj2891:

#include
#include 
#define ll long long 
using namespace std;

int n;

ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b); 
}

void ex_gcd(ll a,ll b,ll &x,ll &y){
    if(!b) x=1,y=0;
    else ex_gcd(b,a%b,y,x),y-=(a/b)*x;
}

ll mul(ll a,ll b,ll p){
    ll ans=0;
    while(b){
        if (b%2) ans=(ans+a)%p;
        a=(a+a)%p;
        b/=2;
    }
    return ans;
}


int main(){
    ll m2,a2,m,ans;
    while(~scanf("%d",&n)){
        bool flag=0;
        scanf("%lld%lld",&m,&ans);
        for (int i=2;i<=n;i++){
            scanf("%lld%lld",&m2,&a2);
            a2=(a2-ans%m2+m2)%m2;//a2-a1 
            ll d=gcd(m2,m),x,y;
            if (a2%d) flag=1;//方程无解
            ex_gcd(m,m2,x,y);
            x=mul(x,a2/d,m2);//解k1*m1-k2*m2=a2-a1 (如果你想过掉【洛谷P4777】这里要加一个龟速乘)
            ans+=x*m;
            m*=m2/d;//m1=lcm(m1,m2) 
            ans=(ans%m+m)%m;
        } 
        if (flag) printf("-1\n");
        else printf("%lld\n",ans);  
    }
    return 0;
}

OK,完事

参考:
https://www.cnblogs.com/freinds/p/6388992.html
https://blog.csdn.net/niiick/article/details/80229217
https://www.cnblogs.com/Miracevin/p/9254795.html
https://www.luogu.org/recordnew/show/19877167
https://www.luogu.org/recordnew/show/19921331

于HG机房

你可能感兴趣的:(崩溃的数学)