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)

截自百度百科:

欧几里得(辗转相除gcd)、扩欧(exgcd)、中国剩余定理(crt)、扩展中国剩余定理(excrt)简要介绍

要求模下的唯一解,关键是求逆元。

拓展欧几里得如何求逆元: 

当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 }

51nod中还有个求乘法逆元的题,直接应用扩欧求逆元即可。

最后上crt完整代码:

 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 }

 例题:51nod 1079中国剩余定理 http://www.51nod.com/Challenge/Problem.html#!#problemId=1079

 1 #include <iostream>
 2 using namespace std;
 3 int n;
 4 long long pri[11],re[11];//分别保存质数,和取余的结果
 5 //利用扩展欧几里得求乘法取模运算的逆元
 6 long long exgcd(long long a,long long b,long long &x,long long &y){
 7     long long d=a;
 8     if(b==0)  y=0,x=1;
 9     else{
10         d=exgcd(b,a%b,y,x);
11         y-=a/b*x;
12     }
13     return d;
14 }
15 //Chinese remainder theorem
16 long long crt(){
17     long long m=1,ans=0;
18     for(int i=0;i<n;i++){
19         m*=pri[i];
20     }
21     for(int i=0;i<n;i++){
22         long long mi=m/pri[i],x,y;
23         exgcd(mi,pri[i],x,y);
24         ans=(ans+re[i]*x*mi)%m;
25     }
26     if(ans<0) ans+=m;
27     return ans;
28 }
29 int main(){
30     cin>>n;
31     for(int i=0;i<n;i++){
32         cin>>pri[i]>>re[i];
33     }
34     cout<<crt()<<endl;
35     return 0;
36 }
View Code

相关文章:

  • 2021-07-20
  • 2022-12-23
  • 2021-12-14
  • 2021-12-18
  • 2021-10-18
  • 2022-01-07
  • 2022-12-23
  • 2021-09-15
猜你喜欢
  • 2021-06-08
  • 2021-11-11
  • 2021-11-08
  • 2021-07-13
  • 2022-12-23
  • 2022-12-23
  • 2022-01-22
相关资源
相似解决方案