模线性方程&&中国剩余定理及拓展
一、求解模线性方程
由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 }
越努力,越幸运