中国剩余定理 【CRT 两种模型的讲解】

来源:互联网 发布:人工智能bob和alice 编辑:程序博客网 时间:2024/06/09 20:29

互质的模的CRT原理讲解很好的文章
问题一:给你n个方程组:
x%m[0] = a[0]
x%m[1] = a[1]
···
x%m[n-1] = a[n-1]
求变量x 的值,其中m[]必须两两互质。
·

LL gcd(LL a, LL b){    return b == 0 ? a : gcd(b, a%b);}void exgcd(LL a, LL b, LL &d, LL &x, LL &y){    if(!b){d = a, x = 1, y = 0;}    else    {        exgcd(b, a%b, d, y, x);        y -= x * (a / b);    }}//l-r为方程组下标 方程 x % m = aLL CRT(LL l, LL r, LL *m, LL *a){    LL M = 1, d, y, x = 0;    for(LL i = l; i <= r; i++)        M =  M / gcd(M, m[i]) * m[i];    for(LL i = l; i <= r; i++)    {        LL w = M / m[i];        exgcd(m[i], w, d, d, y);        x = (x + y * w * a[i]) % M;    }    return (x + M) % M;}

2 当模不是互质的时候,我们可以采取合并方程的思想来解决。
每两个方程合并之后就可以转化为一个不定方程。
证明如下 :

x = a ( mod n)
x = a1 ( mod n1 )
展开 : x = a+ k * n x = a1 + k1 * n1 ;
合并 k*n = a1 - a + k1 * n1
k * n = a1 - a ( mod n1) // 发现没有 不定方程之后直接用exgcd 解就可以。
设 d=gcd(n,n1) . c= a1 - a
由不定方程我们知道 只有当 d | c 才会有解。
k * n = c ( mod n1)
k * n = c + n1 * y 设temp = c / d
k * n + n1 * y = c = temp * d
n * ( k / temp ) + n1 * ( y / temp ) = d //标准的扩展欧几里得运用格式
然后exgcd( n , n1 , d , x0 , y0 ) .
k = temp * x0 = x0 * ( c / d )
这时为了得到正整数k ,取模,k = ( k % ( n1 / d ) + (n1 / d) ) %(n1 / d ) // 注意这里我们只是得到了一个特解 k
然后将k带回第一个方程中
x = a + k * n
这个时候得到的也是特解,那么通解呢?
x = a + k * n + s * ( n1 * n ) / d 【 加了lcm ( n1,n ) 的倍数,这样不会影响其特定余数的特性】
然后 我们将 a + k * n 赋值给 a ,将(n1 * n )/d 赋值给 n
得到 x = a + s * n ==> x = a ( mod n ) 这样的式子,然后就可以无限求方程组下去。

代码

LL gcd(LL a, LL b){    return b == 0 ? a : gcd(b, a%b);}void exgcd(LL a, LL b, LL &d, LL &x, LL &y){    if(!b){d = a, x = 1, y = 0;}    else    {        exgcd(b, a%b, d, y, x);        y -= x * (a / b);    }}LL CRT(LL l, LL r, LL *m, LL *a)//方程 x % m = a{    LL lcm = 1;    for(LL i = l; i <= r; i++)        lcm = lcm / gcd(lcm, m[i]) * m[i];    for(LL i = l+1; i <= r; i++)//合并方程 共需r-l+1次    {        LL A = m[l], B = m[i], d, x, y, c = a[i] - a[l];//合并方程后 各个系数        exgcd(A, B, d, x, y);//d = gcd(A, B);        if(c % d)//对扩展后的式子a*x + b*y = c 当且仅当c % d == 0是才有解            return -1;        LL mod = m[i] / d;        LL k = ((x * c / d) % mod + mod) % mod;        a[l] = m[l] * k + a[l];        m[l] = m[l] * m[i] / d;//更新方程系数 利用该方程继续和下一个方程合并    }    if(a[l] == 0) return lcm;//特判    return a[l];//合并到最后a[l] 就是解}

“`