欧几里得(辗转相除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 }
View Code

 

以上是关于欧几里得(辗转相除gcd)扩欧(exgcd)中国剩余定理(crt)扩展中国剩余定理(excrt)简要介绍的主要内容,如果未能解决你的问题,请参考以下文章

扩展欧几里得(exgcd)与同余详解

浅谈扩展欧几里得算法(exgcd)

Gcd&Exgcd算法

Exgcd(扩展欧几里得算法)

欧几里得算法(辗转相除法)

欧几里得算法(辗转相除法)