欧几里得(辗转相除gcd)扩欧(exgcd)中国剩余定理(crt)扩展中国剩余定理(excrt)简要介绍
Posted noobimp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了欧几里得(辗转相除gcd)扩欧(exgcd)中国剩余定理(crt)扩展中国剩余定理(excrt)简要介绍相关的知识,希望对你有一定的参考价值。
1.欧几里得算法(辗转相除法)
直接上gcd和lcm代码。
1 int gcd(int x,int y){ 2 return y==0?x:gcd(y,x%y); 3 }
1 int lcm(int x,int y){ 2 return x*y/gcd(x,y); 3 }
2.扩欧:exgcd:对于a,b,一定存在整数对(x,y)使ax+by=gcd(a,b)=d ,且a,b互质时,d=1。 x,y可递归地求得。
我懒得改返回值类型了
1 long long exgcd(long long a,long long b,long long &x,long long &y){ 2 long long d=a; 3 if(b==0) y=0,x=1; 4 else{ 5 d = exgcd(b,a%b,y,x); 6 y -= a/b*x; 7 } 8 return d; 9 }
求解 x,y的方法的理解:
设 a>b。
1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2,a>b>0 时
设 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
则:ax1+ by1 = bx2+ (a mod b)y2;
即:ax1+ by1 = bx2+ (a - [a / b] * b)y2
= ay2+ bx2- [a / b] * by2;
= ay2+ b(x2- [a / b] *y2);
所以:x1=y2; y1=x2- [a / b] *y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
这个思想是递归的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
3.中国剩余定理(Chinese remainder theorem)
截自百度百科:
要求模下的唯一解,关键是求逆元。
拓展欧几里得如何求逆元:
当a与b互素时有 gcd(a ,b)=1
即得: a*x+b*y=1
a*x ≡ 1 (mod b)
由于a与b互素,同余式两边可以同除a 得:1*x ≡ 1/a (mod b),因此 x 是 a mod b 的逆元;
求逆元也可单写为函数:a在模b意义下的逆元:inv(a,b);
1 long long inv(long long a, long long b){ 2 exgcd(a,b,x,y); 3 while(x<0) x+=b; 4 return x; 5 }
最后上完整代码:
1 long long crt(){//pri数组和re数组分别保存质数和余数 也就是上图方程组中的mi和ai 2 long long m=1,ans=0; 3 for(int i=0;i<n;i++){ 4 m*=pri[i]; 5 } 6 for(int i=0;i<n;i++){ 7 long long mi=m/pri[i],x,y; 8 exgcd(mi,pri[i],x,y); //exgcd的应用:求得逆元x 9 ans=(ans+re[i]*x*mi)%m;//加和求模下的唯一解 10 } 11 while(ans<0) ans+=m; 12 return ans; 13 }
4.扩展中国剩余定理(excrt)
我太笨了当时看了好久还是不会,现在稍微明白点了但还是迷迷糊糊,具体分析过程看这个dalao的blog:https://www.cnblogs.com/zwfymqz/p/8425731.html
放一个参考人家修修改改写的题目吧。POJ2891
1 #include<iostream> 2 #include<cstdio> 3 #define ll long long 4 using namespace std; 5 6 const ll MAXN = 1e6 + 10; 7 ll K, C[MAXN], M[MAXN], x, y; 8 9 ll gcd(ll a, ll b) { 10 return b == 0 ? a : gcd(b, a % b); 11 } 12 ll exgcd(ll a, ll b, ll &x, ll &y) { 13 ll r=a; 14 if (b == 0) x = 1, y = 0; 15 else{ 16 r = exgcd(b, a % b, y, x); 17 y -= (a / b) * x; 18 } 19 return r; 20 } 21 ll inv(ll a , ll b){//求逆元 22 exgcd(a,b,x,y); 23 while(x<0) x+=b; 24 return x; 25 } 26 27 int main(){ 28 while(cin>>K){ 29 for (ll i = 1; i <= K; i++) scanf("%lld%lld", &M[i], &C[i]); 30 bool flag = 1; 31 for (ll i = 2; i <= K; i++) { 32 ll M1 = M[i - 1], M2 = M[i]; 33 ll C2 = C[i], C1 = C[i - 1]; 34 ll T = gcd(M1, M2); 35 36 if ((C2 - C1) % T != 0) { flag=0; break; } 37 M[i] = (M1 * M2) / T; 38 C[i] = ( inv( M1 / T , M2 / T ) * (C2 - C1) / T ) % (M2 / T) * M1 + C1; 39 C[i] = (C[i] % M[i] + M[i]) % M[i]; 40 } 41 if(flag) cout<<C[K]<<endl; 42 else cout<<-1<<endl; 43 44 } 45 return 0; 46 }
以上是关于欧几里得(辗转相除gcd)扩欧(exgcd)中国剩余定理(crt)扩展中国剩余定理(excrt)简要介绍的主要内容,如果未能解决你的问题,请参考以下文章