EXCRT(扩展中国剩余定理)
拖更了
此时的模数不一定两两互质,导致了不能直接像之前那样只满足其中一个模数然后依次累加。
所以就只能换其他思路
/*
不妨来看其中两个条件满足 x=a1+m1*x1 x=a2+m2*x2
然后直接变换就得到m1*x1-m2*x2=a2-a1 要使得x尽量的小,那么x1和x2都要尽量的小
根据裴蜀定理 ax+by=c有整数解的充要条件就是(a,b)|c 也就是c是gcd(a,b)的整数倍数
所以基于此 设g=gcd(m1,m2)
x1'*m1/g+(-x2'*m2/g)=1 此时的 m1/g=m1'和 m2/g=m2'互质所以此时的gcd(m1',m2')=1此时的(a,b)|c 恒成立
所以就可以利用扩展欧几里得 对比 x1*m1/g+(-x2*m2/g)=(a2-a1)/g 得到 x1=t*m2'+x1'*(a2-a1)/g x2=t*m1'+x2'*(a2-a1)/g
最后直接代入x=a1+m1*x1 得到x=a1+m1*m2'*t+x1'*m1
最后x等价于(a1+x1'*m1)%(m1*m2')
(m1*m2')=lcm(m1,m2)
所以最后我们只需要两个两个联立就可因得到所有的满足条件的x
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn=4e5+7;
inline int read()
{
char c = getchar();
int x = 0,fh = 0;
while(c < '0' | c > '9'){fh |= c == '-';c = getchar();}
while(c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}
return fh?-x:x;
}
#define int long long ///全程开long long 龟速乘都是防止爆long long
int n;
int a[maxn];
int b[maxn];
int _exgcd(int a,int b,int &x,int &y)///x代表解 扩展欧几里得
{
if (!b)
{
x=1;
y=0;
return a ;
}
int gcd=_exgcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
return gcd;///返回最大公约数
}
int gui_sort(int a,int b,int mod)///防止乘法溢出
{
int ans=0;
while (b>0)
{
if(b&1)
ans=(ans+a)%mod;///龟速乘 类似于快速幂 就是将a*k拆分成a+2a+4a++。。。。。。
a=(a+a)%mod;
b>>=1;
}
return ans%mod;
}
int excrt()
{
int ans=a[1];
int lcm=b[1];///第一个模数
int x,y;
for (int i=2;i<=n;++i)
{
int res=(((a[i]-ans)%b[i])+b[i])%b[i];///防止出现负数解 a2-a1
int gcd=_exgcd(lcm,b[i],x,y);
int ret=b[i]/gcd;
if (res%gcd!=0)///不满足裴蜀定理 不存在整数解
return -1;
x=gui_sort(x,res/gcd,ret);///x1'*(a2-a1)/gcd
ans+=x*lcm;///这个就需要自己思考一下了
///按照之前的推论是m1也就是第一个模数所以每一次我们只需要乘以第一个模数,越往后模数变成lcm了
lcm=lcm*ret;///lcm 求取变形之后的模数
ans=(ans%lcm+lcm)%lcm;///防止出现负数
}
return ans;
}
signed main()
{
n=read();
for (int i=1;i<=n;++i)
cin>>b[i]>>a[i];///模数 余数 x=a%b 当时设反了,因为是按照博客来的
int cnt=excrt();
printf("%lld
",cnt);
return 0;
}
能力有限 有误之处请指正