扩展中国剩余定理
扩展中国剩余定理
题外话:扩展中国剩余定理本身是挺好理解的,但是这道题数据很毒瘤,必须用快速(龟速)乘。
为什么需要扩展中国剩余定理?
中国剩余定理是用来解线性同余方程组的解的一种方法,但是它有一个巨大的缺陷,那就是中国剩余定理只能解决线性同余方程组的模两两互质的情况。
所以我们需要另一种办法来解模不互质的线性同余方程组,虽说它是扩展中国剩余定理,但其实并不是从中国剩余定理中演变出来的(这主要是因为中国剩余定理的巨大缺陷,无法优化),更像一种新的算法,更贴切的,它其实是一种合并同余方程的方法,最后我们还是用扩展欧几里得来解的。
如何求解?
求解的过程其实就是在每两个方程合并的过程求一步一步的解,之后通过上一步的解推出当前的解,最后当所有的方程合并为一个时就得出了最终的解。
如何合并
我们先细分成两个同余方程来看:
第一个方程式的解\(a_1+kn_1\),那么第二个方程式的解\(x=a_1+kn_1\),这个理解起来两个方程式的\(x\)是一样的,所以第二个方程式的\(x\)就可以看作第一个方程式的解,至于为什么是\(a_1+kn_1\)这个是同余方程的性质。
然后我们可以得到\(a_1+kn_1\equiv a_2(\mod n_2)\),移项后就变成了\(kn_1\equiv a_2-a_1(\mod n_2)\)由于\(a_2-a_1\)是已知的所以我们可以用扩展欧拉定理来求解\(k\),这样就得到了合并后的方程式的解。
然后我们需要考虑模数,根据同余方程的性质,其实合并后的模数就是\(lcm(n_1,n_2)\),即最小公倍数。
无解?
刚刚我们在合并的过程中求了扩展欧几里得,所以其实方程式是可能无解的,只需要加一个判断\((a_2-a_1)\%\gcd(n_1,n_2)\),根据扩展欧几里得,这个式子等于零时时有解的,反之无解,(这道题保证了有解)。(如果这一部分关于扩展欧几里得的求解问题有疑惑的,在这里不过多赘述,建议温习一下如何求解不定方程\(ax+by=c\))
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MN=1e5+100;
int n,a[MN],b[MN];
inline int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-(a/b)*y;
return d;
}
inline int mul(int a,int b,int mod){
int res=0;
while(b>0){
if(b&1)res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;++i)scanf("%lld",&a[i]),scanf("%lld",&b[i]);
int M=a[1],xn=b[1];
for(int i=2;i<=n;++i){
int x,y;
int gcd=exgcd(M,a[i],x,y),c=(b[i]-xn%a[i]+a[i])%a[i];\\这里注意取模因为xn时上一个解,但是第二个式子的模数不一样
int mod=a[i]/gcd;
if(c%gcd!=0){
printf("no anser");
return 0;
}
x=mul(x,c/gcd,mod);
xn=xn+x*M;
M=M*mod;\\不理解可以写成M=M*lcm(xn,a[i])
xn=(xn%M+M)%M;
}
xn=(xn%M+M)%M;
printf("%lld\n",xn);
return 0;
}

浙公网安备 33010602011771号