中国剩余定理证明及模版

POJ 1006 Biorhythms
中国剩余定理证明及模版_第1张图片

算法证明如上。
在实际求解时,可能不满足n1,n2,n3…nk,互质,那么令N=LCM(n1,n2,…,nk)最小公倍数,即保证算法正确性。
可以发现,求解m时,与a无关,所以,题目若是固定取模的数不动,但是改变a的值,可以预处理出m,然后根据题目计算答案。正是POJ 1006 Biorhythms.
得到的x,可能是正可能负,这只是方程组的一个解,方程组的通解满足X = x + N*t , t为任意整数。

模版

#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int MAXN = 1e5;
/*
x = a1(mod n1)
...
x = ak(mod nk)
x = a1*m1+a2*m2+...+ak*mk
N = LCM(n1, n2, ..., nk)
*/
int num; // 等式的数量
LL a[MAXN];
LL n[MAXN];
LL N; // 调整x的大小时会用到,所以放在全局里
LL LCM(LL* n, int num) {
    LL gcd = n[0];
    LL ans = 1;
    for(int i = 1; i < num; i++)
        gcd = __gcd(gcd, n[i]);
    for(int i = 0; i < num; i++)
        ans *= n[i]/gcd;
    return ans;
}
LL exgcd(LL a, LL b, LL& x, LL& y) {
    if(b == 0) {
        x = 1;
        y = 0;
        return a;
    }else {
        LL r = exgcd(b, a%b, x, y);
        LL t = y;
        y = x-a/b*y;
        x = t;
        return r;
    }
}
LL crt() {  // Chinese Remainder Theorem
    LL N = LCM(n, num);
    LL x = 0;
    for(int i = 0; i < num; i++) {
        LL u, v;
        exgcd(n[i], N/n[i], u, v);
        // mi = N/n[i]*v;
        x += N/n[i]*v*a[i];
    }
    return x;
}
int main() {
    scanf("%d", &num);
    for(int i = 0; i < num; i++) {
        scanf("%lld%lld", &a[i], &n[i]);
    }
    LL x = crt(); // 计算等式一个解


    cout << x << endl;
    return 0;
}

你可能感兴趣的:(ACM)