模线性方程&&中国剩余定理及拓展

一、求解模线性方程

由ax=b(mod n)

可知ax = ny + b

就相当于ax + ny = b

由扩展欧几里得算法可知有解条件为gcd(a, n)整除d

可以直接套用扩展欧几里得算法

最终由d个不同解时在模n下有d个不同的数字

二、中国剩余定理

证明可看:https://www.cnblogs.com/MashiroSky/p/5918158.html

ll extgcd(ll a, ll b, ll& x, ll& y)
//求解ax+by=gcd(a, b)
//返回值为gcd(a, b)
{
    ll d = a;
    if(b)
    {
        d = extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    }
    else x = 1, y = 0;
    return d;
}
ll solve(ll a[], ll m[], int n)//a数组是余数,m数组是两两互质的数字
{
    ll M = 1, ans = 0;
    for(int i = 0; i < n; i++)M *= m[i];
    //cout<<M<<endl;
    for(int i = 0; i < n; i++)
    {
        ll mi = M / m[i], x, y;
        extgcd(mi, m[i], x, y);
        //求出mi模上m[i]的逆元x  mi * x + m[i] * y = gcd(mi, m[i]) = 1(两两互质)
        ans = ans + ((a[i] % M) * (mi % M) % M) * (x % M) % M;
        ans = (ans % M + M) % M;
    }
    return ans;
}

三、中国剩余定理扩展---求解一般的模线性方程组

  普通的中国剩余定理要求所有的互素,那么如果不互素呢,怎么求解同余方程组?

  这种情况就采用两两合并的思想,假设要合并如下两个方程:

  那么得到:

  我们需要求出一个最小的xx使它满足:

在代码中,每次求出m0 * x + m[i] * y = a[i] - a0的解x的时候,对x模上m[i],这是为了保证x绝对值较小,防止之后的乘法溢出,

x的通解就是x + k * m[i] / gcd(m0, m[i]),此处模上m[i] / gcd(m0, m[i])更好

 1 ll extgcd(ll a, ll b, ll& x, ll& y)
 2 //求解ax+by=gcd(a, b)
 3 //返回值为gcd(a, b)
 4 {
 5     ll d = a;
 6     if(b)
 7     {
 8         d = extgcd(b, a % b, y, x);
 9         y -= (a / b) * x;
10     }
11     else x = 1, y = 0;
12     return d;
13 }
14 ll solve(ll a[], ll m[], int n)//a数组是余数,m数组是除数
15 {
16     ll m0 = m[0], a0 = a[0];
17     for(int i = 1; i < n; i++)
18     {
19         ll x, y;
20         ll g = extgcd(m0, m[i], x, y);//求出m0 * x + m[i] * y = gcd(x, y)
21         if((a[i] - a0) % g)return -1;
22         x = x * (a[i] - a0) / g % m[i];  
23         //求出m0 * x + m[i] * y = a[i] - a0的解x
24         //此处模上m[i]是为了取绝对值最小的一个x,因为x的通解就是x+k*m[i]
25         ll K = x * m0 + a0;     //代回原式,求出最大的K
26         m0 = m0 / g * m[i];     //m0更新为m0和m[i]的lcm
27         a0 = K;                 //a0更新为K
28         a0 = ((a0 % m0) + m0) % m0;
29     }
30     return a0;
31 }

猜你喜欢

转载自www.cnblogs.com/fzl194/p/9017049.html