加载中...

中国剩余定理 (韩信点兵定理)

给出一系列线性同余方程:
x≡a[1](mod m[1])
x≡a[2](mod m[2])
x≡a[3](mod m[3])

求x的最小值

令M=m[1]∗m[2]∗…∗m[n]
令M[i]=M/m[i], 因为m[]中的数两两互质,所以M[i]与m[i]互质,所以可以用扩欧求出M[i]的逆元
t[i]是M[i]在模m[i]下的逆元,即M[i]∗t[i]≡1(mod m[i])
x=∑a[i]M[i]t[i] 余数分乘积逆元

void exgcd(LL a, LL b, LL &x, LL &y) {//
    if (!b) x = 1, y = 0;
    else {
        exgcd(b, a % b, y, x);
        y -= a / b * x;
    }
}
int main() {
    cin >> n;
    LL M = 1;
    for (int i = 0; i < n; ++ i) {
        cin >> m[i] >> a[i];
        M *= m[i];  //读入mi的同时计算M
    }
    LL res = 0;
    for (int i = 0; i < n; ++ i) {
        LL Mi = M / m[i];   //计算Mi = M/mi
        LL ti, y;
        //这一步是求逆元,根据逆元公式的衍生公式可以得到 ti * Mi + y * mi = 1
        exgcd(Mi, m[i], ti, y);
        res += a[i] * Mi * ti;  //计算的同时累加到res中(上述公式里有个sum需要累加)
    }
    cout << (res % M + M) % M << endl;  //对于任意x+kM都是满足要求的解,但目标是输出最小的正整数x,因此取模即可
    return 0;
}


posted @ 2022-08-08 23:47  liang302  阅读(450)  评论(0)    收藏  举报