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

原文地址:https://www.cnblogs.com/noobimp/p/10301297.html

时间: 2024-10-08 22:05:27

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

Last Defense 西安现场赛 欧几里得出发的应用

这道题的意思是给你两个数A, B, s0 = A, s1 = B, si = |si-1 - si-2|, 让你求出里面有几个不同的数, 首先我们可以确定对于数y和x,y一定能写成kx+b的形式,在数列的生成过程中,会出现kx+b.x.(k-1)x+b.(k-2)x+b.x.....2x+b.x.x+b.b.x,其中出现的不同数字个数就是(kx+b)/ x,之后问题变成了数x和b的问题,最后可以发现这就是一个辗转相除法的过程.每做一次辗转相除gcd(x,y),不同数字个数就多了x/ y.最后加上

[poj1061]青蛙的约会&lt;扩展欧几里得&gt;

题目链接:http://poj.org/problem?id=1061 其实欧几里得我一直都知道,只是扩展欧几里得有点蒙,所以写了一道扩展欧几里得裸题. 欧几里得算法就是辗转相除法,求两个数的最大公约数,算法是,a,b的最大公约数是gcd(b,a%b)然后不断递归下去,直到b=0 转换成c++语言就是 1 int ex_gcd(int a,int b) 2 { 3 if(b==0)return a; 4 return ex_gcd(b,a%b); 5 } 扩展欧几里得就是假设c=gcd(a,b)

同余方程(扩展欧几里得)

#include<cstdio> using namespace std; int x,y; int gcd(int a,int b,int &x,int &y){ if(!b){ x=1,y=0; return a; } int ret=gcd(b,a%b,x,y); int t=x; x=y; y=t-a/b*y; return ret; } int a,b; int main(){ scanf("%d%d",&a,&b); gcd(a,

关于扩展欧几里得

给出两个整数a,b 扩展欧几里得可以求出gcd(a,b),并且能顺带算出一组特解(x,y), 使ax+by=gcd(a,b). 其实扩展欧几里得算法就是收集辗转相除法中产生的式子,倒回去,可以得到ax+by=gcd(a,b)的整数解. 原理如下: 设a=r0,b=r1, 那么根据辗转相除法, r0=q1*r1+r2     (即a=q1*b+r2) r1=q2*r2+r3 r2=q3*r3+r4 ....... rk-4=qk-3*rk-3+rk-2 rk-3=qk-2*rk-2+rk-1 rk

[模板]欧几里得算法/扩展欧几里得

最大公因数(欧几里得算法) $gcd(a,b)=gcd(b\%a,a)$(不一定需要a<b) $gcd(0,b)=b$ 1 inline int gcd(int a,int b){ 2 return a==0?b:gcd(b%a,a); 3 } 扩展欧几里得 寻找$ax+by=gcd(a,b)$的一组解x,y(一定存在整数解) $ax+by=gcd(a,b)=gcd(b\%a,a)=(b-\lfloor\frac{b}{a}\rfloor*a)x'+ay'$ 所以有一组解$x=y'-\lfloo

gcd,扩展欧几里得,中国剩余定理

1.gcd: int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } 2.中国剩余定理: 题目:学生A依次给n个整数a[],学生B相应给n个正整数m[]且两两互素,老师提出问题:有一正整数ans,对于每一对数,都有:(ans-a[i])mod m[i]=0.求此数最小为多少. 输入样例: 1 10 2 3 1 2 3 2 3 5 8 1 2 3 4 5 6 7 8 97 89 67 61 59 53 47 88 12 1 2 3 4 5 6 7 8 9

hdu 5512 Pagodas 扩展欧几里得推导+GCD

题目链接 题意:开始有a,b两点,之后可以按照a-b,a+b的方法生成[1,n]中没有的点,Yuwgna 为先手, Iaka后手.最后不能再生成点的一方输: (1 <= n <= 20000) T组数据T <= 500; 思路:由扩展欧几里得知道对于任意正整数,一定存在整数x,y使得 x*a + y*b = gcd(a,b);并且这个gcd是a,b组成的最小正整数:同时也知道了这也是两个点之间的最小距离: 之后直接求点的个数即可: ps:这道题我竟然想到了组合游戏..明显没有说双方都要用

uva 10951 - Polynomial GCD(欧几里得)

题目链接:uva 10951 - Polynomial GCD 题目大意:给出n和两个多项式,求两个多项式在所有操作均模n的情况下最大公约数是多少. 解题思路:欧几里得算法,就是为多项式这个数据类型重载取模运算符,需要注意的是在多项式除多项的过程中,为了保证各项系数为整数,需要将整个多项式的系数整体扩大至一定倍数,碰到先除后模的时候要用逆元. #include <cstdio> #include <cstring> const int maxn = 105; int M; void

POJ 2115 (模线性方程 -&gt; 扩展欧几里得)

题意: for(i=A ; i!=B ;i +=C)循环语句,问在k位操作系统中循环结束次数. 若在有则输出循环次数. 否则输出死循环. 存在这样的情况:i= 65533 :i<=2:i+= 4:时i = 2: 由模线性方程->扩展欧几里得 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using