扩展欧几里得(ex_gcd),中国剩余定理(CRT)讲解 有代码
扩展欧几里得算法
求逆元就不说了。
ax+by=c
这个怎么求,很好推。
设d=gcd(a,b) 满足d|c方程有解,否则无解。
扩展欧几里得求出来的解是 x是 ax+by=gcd(a,b)的解。
对于c的话只需要x*c/gcd(a,b)%(b/d)即可,因为b/d的剩余系更小。
为什么这样呢?
设a'=a/d,b'=b/d 求出a'x+b'y=1的解,两边同时乘d,然后x也是ax+by=d的解,
然后因为b'的剩余系更小,所以%b’
中国剩余定理是合并线性方程组的
中国余数定理
转化为一个线性方程 ax+by=c
a,b
c,d
num % a=b;
num % c=d;
求num最小正整数解;
num=ax+b=cy+d
ax-cy=d-b
可以化为求解 ax≡(d-b)(mod c);
ax+cy=d-b
用ex_gcd求解出x;
num=a*x+b;
这样num mod a=b
num mod c=d-b+b=d
因为x为最小正整数解,所以num为最小解
满足的集合为{x|x=num+k·[a,b],(k∈Z)}
然后转化为%lcm(a,c)=num
然后继续合并
附上代码,完美代码
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cmath> 5 typedef long long ll; 6 using namespace std; 7 ll ex_gcd(ll a,ll b,ll &x,ll &y) 8 { 9 if (!b) 10 { 11 x=1,y=0; 12 return a; 13 } 14 ll fzy=ex_gcd(b,a%b,x,y); 15 ll t=x; 16 x=y;y=t-a/b*y; 17 return fzy; 18 } 19 int main() 20 { 21 int t; 22 ll z1,z2,z3,z4; 23 while (cin>>t) 24 { 25 bool flag=0; 26 scanf("%lld%lld",&z1,&z2); 27 for (int i=1;i<t;i++) 28 { 29 scanf("%lld%lld",&z3,&z4); 30 if (flag) continue; 31 ll a=z1,b=z3,c=z4-z2; 32 ll x,y; 33 ll d=ex_gcd(a,b,x,y); 34 if (c%d!=0) 35 { 36 flag=1; 37 continue; 38 } 39 ll t=b/d; 40 x=(x*(c/d)%t+t)%t;//t的剩余系更小。 41 z2=z1*x+z2;//得出num 42 z1=z1*(z3/d); 43 cout<<"z1="<<z1<<" z2="<<z2<<endl; 44 } 45 if (flag==1) cout<<-1<<endl; 46 else cout<<z2<<endl; 47 } 48 }