数论基础之中国剩余定理(附证明)

前言

一直觉得中国剩余定理很难,因为怕麻烦一直没有去搞,直到区域赛网络赛在即,直到……退役赛在即。(果然DDL是原生动力,可能是爱得不够深吧)学了一下,觉得其实也没那么难,如果理解不了证明的话,看懂每个变量表示的含义,利用结论 x = ∑ i = 1 n a i M i t i x= \sum_{i=1}^n a_iM_it_i x=i=1naiMiti求解也可。

定理与证明

定理:若 m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1,m2,...,mn是两两互质的正整数, M = ∏ i = 1 n m i , M i = M / m i , t i M=\prod_{i=1}^nm_i,M_i=M/m_i,t_i M=i=1nmi,Mi=M/miti是线性同余方程 M i t i ≡ 1 ( m o d   m i ) M_it_i\equiv1(mod \, m_i) Miti1(modmi)的一个解。对于任意n个整数 a 1 . a 2 , . . . , a n a_1.a_2,...,a_n a1.a2,...,an,则同余方程组
{ x ≡ a 1 ( m o d   m 1 ) x ≡ a 2 ( m o d   m 2 ) . . . x ≡ a n ( m o d   m n ) \begin{cases} x \equiv a_1(mod \, m_1) \\ x \equiv a_2(mod \, m_2) \\ ...\\ x \equiv a_n(mod \, m_n) \\ \end{cases} xa1(modm1)xa2(modm2)...xan(modmn)
有整数解,方程组的解为 x = a 1 M 1 t 1 + a 2 M 2 t 2 + . . . + a n M n t n x=a_1M_1t_1+a_2M_2t_2+...+a_nM_nt_n x=a1M1t1+a2M2t2+...+anMntn。且在模 M M M意义下有唯一解。
PS:要看清楚 M , M i , t i M,M_i,t_i M,Mi,ti分别表示什么含义,才容易理解。

证明

∵ \because M i = M / m i M_i=M/m_i Mi=M/mi 是除 m i m_i mi 以外所有模数的倍数
∴ \therefore ∀   k ≠ i ,   a i M i t i ≡ 0 ( m o d   m k ) \forall \, k \neq i, \,a_iM_it_i \equiv0(mod \, m_k) k=i,aiMiti0(modmk)
∵ \because a i M i t i ≡ a i ( m o d   m i ) a_iM_it_i \equiv a_i(mod \, m_i) aiMitiai(modmi)
( a + b ) % p = a % p + b % p (a + b) \%p=a \%p+b \%p (a+b)%p=a%p+b%p
∴ \therefore x = ∑ i = 1 n a i M i t i x= \sum_{i=1}^n a_iM_it_i x=i=1naiMiti代入,原方程组成立
证毕。
(摘自:信息学奥赛一本通·提高版)

PS:如果不理解证明的话,可以尝试把 x = ∑ i = 1 n a i M i t i x= \sum_{i=1}^n a_iM_it_i x=i=1naiMiti代回任意一项 k k k,你会发现除了 ( a k M k t k ) % m k = a k (a_kM_kt_k)\%m_k=a_k (akMktk)%mk=ak外,别的项都是等于0,最终相加等于 a i a_i ai。(看不懂就慢慢模拟一遍嘛)

代码模板

/*
 * m[i]是模数,a[i]是系数
 * 注意:m[i]之间必须两两互质
 */
ll Crt(int n) {
    ll ans = 0, M = 1, Mi, xi, yi;
    for (int i = 1; i <= n; i++) M *= m[i];
    for (int i = 1; i <= n; i++) {
        Mi = M / m[i];
        extend_gcd(Mi, m[i], xi, yi);
        //保证求得的解为正整数
        ans = ((ans + Mi * xi * a[i]) % M + M) % M;
    }
    return ans;
}

模板题#10212. 「一本通 6.4 例 4」曹冲养猪

代码如下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long ll;
const int maxn = 1005;
int n, a[maxn], m[maxn];
//快读
template <class T>
inline bool read(T &res) {
    char c; int sgn;
    if (c = getchar(), c == EOF) return 0;
    while (c != '-' && (c < '0' || c > '9')) c =getchar();
    sgn = (c == '-') ? -1 : 1;
    res = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') res = res * 10 + (c - '0');
    res *= sgn;
    return 1;
}
//快写
inline void write(ll x) {
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
//拓展欧几里德
ll extend_gcd(ll a, ll b, ll &x, ll &y) {
    if (x == 0 && y == 0) return -1;
    if (b == 0) {
        x = 1; y = 0;
        return a;
    }
    ll d = extend_gcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

ll China(int n) {
    ll ans = 0, M = 1, Mi, xi, yi;
    for (int i = 1; i <= n; i++) M *= m[i];
    for (int i = 1; i <= n; i++) {
        Mi = M / m[i];
        extend_gcd(Mi, m[i], xi, yi);
        ans = ((ans + Mi * xi * a[i]) % M + M) % M;
    }
    return ans;
}

int main()
{
    read(n);
    for (int i = 1; i <= n; i++) {
        read(m[i]); read(a[i]);
    }
    write(China(n));
    return 0;
}

//哪有那么快,看不懂就静心细看
//想看定理的由来可以直接看数论的书

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:白松林 返回首页