中国剩余定理及扩展

文章目录

  • 中国剩余定理
    • 用途
    • 求解方法
    • 例题&代码
      • [洛谷P1495 曹冲养猪](https://www.luogu.org/problemnew/show/P1495)
      • 洛谷P3868 [TJOI2009]猜数字
  • 扩展中国剩余定理
    • 用途
    • 求解方法
    • 例题&代码
      • 洛谷P4777 【模板】扩展中国剩余定理(EXCRT)
  • 完结撒花
    • GL && HF!!!

中国剩余定理

用途

​ 中国剩余定理一般用于求解模数互质线性同余方程组。形式如下:
{ x ≡ a 1 ( m o d b 1 ) x ≡ a 2 ( m o d b 2 ) … x ≡ a i ( m o d b i ) … x ≡ a n ( m o d b n ) \begin{cases} x \equiv {a_1} \pmod {b_1} \\ x \equiv {a_2} \pmod {b_2} \\ \ldots \\ x \equiv {a_i} \pmod {b_i} \\ \ldots \\ x \equiv {a_n} \pmod {b_n} \end{cases} xa1(modb1)xa2(modb2)xai(modbi)xan(modbn)

求解方法

​ 首先设 M M M为所有模数的乘积,即 ∏ i = 1 n b i \prod \limits_{i=1}^{n} b_i i=1nbi

​ 我们构造一个 x = ∑ i = 1 n a i ⋅ t i ⋅ m i x=\sum \limits_{i=1}^{n} {a_i} \cdot {t_i} \cdot {m_i} x=i=1naitimi,其中 m i = M b i m_i=\frac{M}{b_i} mi=biM t i ⋅ m i ≡ 1 ( m o d b i ) t_i\cdot m_i \equiv 1 \pmod{ b_i} timi1(modbi),可以证明 x x x为方程组的一个特解。证明如下:

​ 由于 m i = M b i m_i=\frac{M}{b_i} mi=biM,且模数均两两互质,那么其余模数必然是 b i b_i bi的倍数。又因为 t i ⋅ m i ≡ 1 ( m o d b i ) t_i\cdot m_i \equiv 1 \pmod{ b_i} timi1(modbi),所以 x ≡ a i ( m o d b i ) x \equiv a_i \pmod{b_i} xai(modbi)。得证。

​ 观察 x x x的构造过程,发现只有 t i t_i ti是未知量,于是我们可以单独对于每一个方程,利用扩展欧几里得算法,求出每一个 b i b_i bi对应的 t i t_i ti,同时 a n s ans ans累加上 a i ⋅ t i ⋅ m i {a_i} \cdot {t_i} \cdot {m_i} aitimi

例题&代码

洛谷P1495 曹冲养猪

中国剩余定理板子题,不过代码中的数组名称与上文的描述有些区别。

洛谷P3868 [TJOI2009]猜数字

还是模板题。

//曹冲养猪
#include 
#define ll long long
#define MAXN 15
using namespace std;

int n;
ll mod[MAXN], b[MAXN], ans;

ll exgcd(ll a, ll b, ll &x, ll &y){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    ll res = exgcd(b, a%b, x, y);
    ll t = x;
    x = y;
    y = t-a/b*y;
    return res;
}

void solve(){		//中国剩余定理 
    ll m = 1;
    for(int i = 1; i <= n; i++){
        m *= mod[i];
    }
    ll x, y, mi;
    for(int i = 1; i <= n; i++){
        mi = m/mod[i];
        exgcd(mi, mod[i], x, y);
        ans += (mi*x*b[i]);
        ans %= m;
    }
    ans = (ans+m)%m;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++){
        scanf("%d%d", &mod[i], &b[i]);
    }
    solve();
    cout << ans << endl;
    
    return 0;
}

扩展中国剩余定理

用途

​ 为什么需要这样一个扩展的定理呢?很明显,中国剩余定理的描述中有一个至关重要的限制条件:模数两两互质。 然而实际上,即使模数不互质,也能对方程组进行求解。这就是扩展中国剩余定理。但实际上,除了解决的问题基本相同,扩展中国剩余定理在证明和实现上都不仅仅是“扩展”,所以XX通索性称其为扩展欧几里得解线性同余方程。

求解方法

​ 首先,我们改变一些定义,设当前正在处理第 i i i个方程,则令 M M M表示前 i − 1 i-1 i1个模数的最小公倍数。令 x x x为前 i − 1 i-1 i1个方程的特解, x ′ x' x为所求的前 i i i组方程的特解。于是对于第 i i i个方程,问题转化为求一个 t t t,使得 x + m ∗ t ≡ a i ( m o d b i ) {x+m*t} \equiv {a_i} \pmod {b_i} x+mtai(modbi),而 x ′ = x + m ∗ t x'={x+m*t} x=x+mt

​ 该方程等价于 m ∗ t ≡ a i − x ( m o d b i ) m*t \equiv {a_i-x} \pmod {b_i} mtaix(modbi),显然只有 t t t是未知量于是我们就可以利用扩欧求出 t t t。一直重复 n n n遍,最终就可以得到方程组的解。

例题&代码

洛谷P4777 【模板】扩展中国剩余定理(EXCRT)

真·模板题。

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

ll n, m, ans;
ll a[MAX], b[MAX];

ll exgcd(ll a, ll b, ll &x, ll &y){
    if(!b){
        x = 1, y = 0;
        return a;
    }
    ll res = exgcd(b, a%b, x, y);
    ll t = x;
    x = y, y = t-a/b*y;
    return res;
}

ll mul(ll a, ll b, ll mod){
    ll res = 0, base = a;
    while(b){
        if(b&1){
            res = (res+base)%mod;
        }
        base = (base+base)%mod;
        b >>= 1;
    }
    return res;
}

ll excrt(){
    m = b[1], ans = a[1];
    for(int i = 2; i <= n; i++){
        ll p = ((a[i]-ans)%b[i]+b[i])%b[i];
        ll x, y;			//mx=p (mod b[i])
        ll gcd = exgcd(m, b[i], x, y);
        if(p % gcd) return -1;
        x = mul(x, p/gcd, b[i]/gcd);
        ans += x*m;
        m *= b[i]/gcd;
        ans = (ans%m+m)%m;
    }
    return (ans%m+m)%m;
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++){
        scanf("%lld%lld", &b[i], &a[i]);
    }
    printf("%lld\n", excrt());
    
    return 0;
}

完结撒花

GL && HF!!!

你可能感兴趣的:(模板,数论)