拓展中国剩余定理

本文参考自:https://www.cnblogs.com/zwfymqz/p/8425731.html
我们知道,中国剩余定理是用来解同余方程组
f ( x ) = { x ≡ c 1 ( m o d   m 1 ) x ≡ c 2 ( m o d   m 2 ) … … … … … x ≡ c r ( m o d   m r ) f(x)=\left\{ \begin{aligned} x ≡ c_1(mod\ m_1)\\ x ≡ c_2(mod\ m_2)\\ ……………\\ x ≡ c_r(mod\ m_r) \end{aligned} \right. f(x)=xc1(mod m1)xc2(mod m2)xcr(mod mr)
但是要求是 m 1 , m 2 , … , m r m_1,m_2,…,m_r m1,m2,,mr两两互质
如果他们不互质呢?
就要用到拓展中国剩余定理

首先我们先考虑如果同余方程只有两个式子的情况
x ≡ c 1 ( m o d   m 1 ) x ≡ c 2 ( m o d   m 2 ) 将 这 两 个 式 子 变 形 x = c 1 + m 1 k x = c 2 + m 2 k 联 立 c 1 + m 1 k = c 2 + m 2 k 移 项 m 1 k = c 2 − c 1 + m 2 k x ≡ c_1(mod\ m_1)\\ x ≡ c_2(mod\ m_2)\\ 将这两个式子变形\\ x = c_1 + m_1k\\ x = c_2 + m_2k\\ 联立\\ c_1 + m_1k = c_2 + m_2k\\ 移项\\ m_1k = c_2 - c_1 + m_2k xc1(mod m1)xc2(mod m2)x=c1+m1kx=c2+m2kc1+m1k=c2+m2km1k=c2c1+m2k
我们用(a,b)表示a,b的最大公约数
这里需要注意,这个方程有解的条件是
(m1,m2) | (c2 - c1),因为后面会用到
( c 2 − c 1 ) ( m 2 , m 1 ) \frac{(c_2 - c_1)}{(m_2,m_1)} (m2,m1)(c2c1)这一项,如果不能整除的话肯定会出现小数
对于上面的方程,两边同时除(m1,m2)
m 1 k 1 ( m 1 , m 2 ) = c 2 − c 1 ( m 1 , m 2 ) + m 2 k 2 ( m 1 , m 2 ) \frac{m_1k_1}{(m_1,m_2)} = \frac{c_2 - c_1}{(m_1,m_2)} + \frac{m_2k_2}{(m_1,m_2)} (m1,m2)m1k1=(m1,m2)c2c1+(m1,m2)m2k2
m 1 ( m 1 , m 2 ) k 1 = c 2 − c 1 ( m 1 , m 2 ) + m 2 ( m 1 , m 2 ) k 2 \frac{m_1}{(m_1,m_2)}k_1 = \frac{c_2 - c_1}{(m_1,m_2)} + \frac{m_2}{(m_1,m_2)}k_2 (m1,m2)m1k1=(m1,m2)c2c1+(m1,m2)m2k2
转换一下
m 1 ( m 1 , m 2 ) k 1 = c 2 − c 1 ( m 1 , m 2 ) ( m o d m 2 ( m 1 , m 2 ) ) \frac{m_1}{(m_1,m_2)}k_1 = \frac{c_2 - c_1}{(m_1,m_2)} (mod \frac {m_2}{(m_1,m_2)}) (m1,m2)m1k1=(m1,m2)c2c1(mod(m1,m2)m2)
此时我们已经成功把k2消去了。
同余式两边同除 m 1 ( m 1 , m 2 ) \frac{m_1}{(m_1,m_2)} (m1,m2)m1
k 1 ≡ i n v ( m 1 ( m 1 , m 2 ) , m 2 ( m 1 , m 2 ) ) ∗ ( c 2 − c 1 ) ( m 1 , m 2 ) ( m o d   m 2 ( m 1 , m 2 ) ) k_1 ≡ inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} (mod\ \frac{m_2}{(m_1,m_2)}) k1inv((m1,m2)m1,(m1,m2)m2)(m1,m2)(c2c1)(mod (m1,m2)m2)
inv(a,b)表示a在模b意义下的逆元
k 1 ≡ i n v ( m 1 ( m 1 , m 2 ) , m 2 ( m 1 , m 2 ) ) ∗ ( c 2 − c 1 ) ( m 1 , m 2 ) + m 2 ( m 1 , m 2 ) ∗ y k_1 ≡ inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} + \frac{m_2}{(m_1,m_2)} * y k1inv((m1,m2)m1,(m1,m2)m2)(m1,m2)(c2c1)+(m1,m2)m2y
接下来怎么办呢?这个狮子已经化到最简了。。
不要忘了,我们刚开始还有两个式子。我们把k1代回去!
x = i n v ( m 1 ( m 1 , m 2 ) , m 2 ( m 1 , m 2 ) ) ∗ ( c 2 − c 1 ) ( m 1 , m 2 ) ∗ m 1 + y m 1 m 2 ( m 1 , m 2 ) + c 1 x = inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} * m_1 + y\frac{m_1m_2}{(m_1,m_2)} + c_1 x=inv((m1,m2)m1,(m1,m2)m2)(m1,m2)(c2c1)m1+y(m1,m2)m1m2+c1
x ≡ i n v ( m 1 ( m 1 , m 2 ) , m 2 ( m 1 , m 2 ) ) ∗ ( c 2 − c 1 ) ( m 1 , m 2 ) ∗ m 1 + c 1 ( m o d m 1 m 2 ( m 1 , m 2 ) ) x ≡ inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)} * m_1 + c_1(mod \frac{m_1m_2}{(m_1,m_2)}) xinv((m1,m2)m1,(m1,m2)m2)(m1,m2)(c2c1)m1+c1(mod(m1,m2)m1m2)
此时,整个式子中的元素我们已经就知道了
具体一点,这个式子可以看作
x ≡ c(mod m)
其中
c = ( i n v ( m 1 ( m 1 , m 2 ) , m 2 ( m 1 , m 2 ) ) ∗ ( c 2 − c 1 ) ( m 1 , m 2 ) ) (inv(\frac{m_1}{(m_1,m_2)},\frac{m_2}{(m_1,m_2)})*\frac{(c_2-c_1)}{(m_1,m_2)}) (inv((m1,m2)m1,(m1,m2)m2)(m1,m2)(c2c1)) % m 2 ( m 1 , m 2 ) ∗ m 1 + c 1 \frac{m_2}{(m_1,m_2)} * m_1 + c_1 (m1,m2)m2m1+c1
m = m 1 m 2 ( m 1 , m 2 ) m = \frac{m_1m_2}{(m_1,m_2)} m=(m1,m2)m1m2
推广一下
我们每次把两个同余式合并,求解之后得到一个新的同余式。在把新的同余式和其他的联立,最终就可以求出满足条件的解

int n;
ll m[maxn],c[maxn];
ll gcd(ll a,ll b){
    return b==0 ? a:gcd(b,a%b);
}
ll mul(ll x,ll y,ll z){
    ll sm = (ld)x/z*y;
    return ((ull)x*y-(ull)sm*z+z)%z;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x = 1;
        y = 0;
        return a;
    }
    ll g = exgcd(b,a%b,y,x);
    y -= a/b * x;
    return g;
}
ll inv(ll a,ll b){
    ll x,y;
    ll g = exgcd(a,b,x,y);
    ll tp = b/g;
    x = (x%tp+tp)%tp;
    return x;
}
ll excrt()
{
    for(int i=2;i<=n;i++){
        //取出m1,m2,c1,c2
        ll m1 = m[i-1], m2 = m[i];
        ll c2 = c[i], c1 = c[i - 1];
        ll T = gcd(m1,m2);
        
        //判断(m1,m2)|(c2-c1)
        if((c2-c1)%T)   return -1;
        
        //m = (m1m2)/(m1,m2)
        m[i] = m1/T*m2;
        //c = (inv(……)……)
        c[i] = mul(inv(m1/T,m2/T),(c2-c1)/T,(m2/T))*m1+c1;
        
        c[i] = (c[i]%m[i]+m[i])%m[i];
    }
    return c[n];
}

纯模板题:https://www.luogu.org/problem/P4777
在这里插入图片描述

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<ctime>
#define ll long long
#define ld long double
#define ull unsigned long long
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100100;
ll m[maxn],c[maxn];
int n;
ll gcd(ll a,ll b){
    return b==0 ? a:gcd(b,a%b);
}
ll mul(ll x,ll y,ll z){
    ll sm = (ld)x/z*y;
    return ((ull)x*y-(ull)sm*z+z)%z;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x = 1;
        y = 0;
        return a;
    }
    ll g = exgcd(b,a%b,y,x);
    y -= a/b * x;
    return g;
}
ll inv(ll a,ll b){
    ll x,y;
    ll g = exgcd(a,b,x,y);
    ll tp = b/g;
    x = (x%tp+tp)%tp;
    return x;
}
ll excrt()
{
    for(int i=2;i<=n;i++){
        ll m1 = m[i-1], m2 = m[i];
        ll c2 = c[i], c1 = c[i - 1];
        ll T = gcd(m1,m2);
        if((c2-c1)%T)   return -1;
        m[i] = m1/T*m2;
        c[i] = mul(inv(m1/T,m2/T),(c2-c1)/T,(m2/T))*m1+c1;
        c[i] = (c[i]%m[i]+m[i])%m[i];
    }
    return c[n];
}
int main(void)
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&m[i],&c[i]);
    ll ans = excrt();
    if(ans!=-1) printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逃夭丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值