gcd+exgcd+例题(青蛙的约定)

1.gcd的两种求法:

一、更相减损法

两个正整数$a$和$b$($a>b$),它们的最大公约数等于$a-b$的差值$c$和较小数$b$的最大公约数。

1 int gcd(int a,int b)
2 {
3     if(a==b)
4         return a;
5     if(a>b)
6         return gcd(a-b,b);
7     if(a<b)
8         return gcd(b-a,a);
9 }

二、辗转相除法

两个正整数$a$和$b$($a>b$),它们的最大公约数等于$a$除以$b$的余数$c$和$b$之间的最大公约数。

1 int gcd(int a,int b)
2 {
3     if(a%b==0)
4         return b;
5     else
6         return gcd(a%b,b);
7 }

2.exgcd

裴蜀定理:对于任意的整数$a$,$b$,都存在一对整数$x$,$y$,使得$ax+by=gcd(a,b)$成立。
可以看出,这是一个递归求解的函数。在函数递归到最后的时候,存在$b=0$,不管$a$是什么,这时显然有一对整数$x=1$,$y=0$来使得:

$a×1+0×0=gcd(a,0)$

那么,我们通过这个递归的实现过程来进行回溯的模拟。当$b>0$ ,则程序还可以继续往下走:$gcd(b,a%b)=gcd(a,b)$。这时假设存在一对整数$x,y$ ,使得其一定会满足$b×x+(a%b)×y=gcd(b,a%b)$, 因为$a%b=a−b⌊a/b⌋ $,所以有以下的推导:$b×x+(a%b)×y=gcd(b,a%b)=bx+(a−b⌊a/b⌋)y=ay−b(x−⌊a/b⌋y)$这个时候令$x′=y,y′=x−⌊a/b⌋$,再结合一开始的原式子,就得出:$ax′+by′=gcd(a,b)$

*裴蜀定理的应用:

                          $ax+by=exgcd(a,b)$

那么可以推出:如果一个数$m$满足:$ax+by=m$,那么这个$m$一定是$gcd(a,b)$的倍数。
那么对于一个经典方程$ax+by=1$,利用裴蜀定理,我们有:$gcd(a,b)=1$,即$a,b$一定互质。 

扩展欧几里得算法

在介绍扩展欧几里得算法之前,我想首先介绍它的应用:
1、求解不定方程
2、求解模的逆元
3、求解线性同余方程
为什么它能应用到这几个方面呢?回到裴蜀定理:$ax+by=m$
 对于这个不定方程,如果存在一组合法的解$(x,y)$,那么一定会有$gcd(a,b)|m$,即$m$是$gcd(a,b)$的倍数。那么现在我不仅想知道到底有没有解,而是想知道在有解的情况下,这个解到底是多少。

 

1 void exgcd(int a,int b,int &x,int &y){
2     if (!b){x=1;y=0;return;}
3     exgcd(b,a%b,y,x);
4     y-=(a/b)*x;
5     return;
6 }

*青蛙的约定

• 设$x_0$为最终结果,让青蛙相对运动,可列
出式子:
• $(m - n)x_0 = y - x (mod L)$
• 显然该式可以转化为:
• $(m - n)x_0 + Ly = y - x$
• 再变换一下变成:
• $ax + by = c$

• 变成了熟悉的$exgcd$问题,正常求解即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include <algorithm>
 4 #define ll long long 
 5 using namespace std;
 6 ll ans,x1,y1;
 7 ll exgcd(ll a,ll b,ll &x1, ll &y1)
 8 {
 9     if(!b)
10     {
11         x1=1;
12         y1=0;
13         return a;
14     }
15     ans=exgcd(b,a%b,x1,y1);
16     ll t=x1;
17     x1=y1;
18     y1=t-a/b*y1;
19     return ans;
20 }
21 
22 int main()
23 {
24     ll n,m,x,y,l;
25     cin>>x>>y>>m>>n>>l;
26     ll b=n-m,a=x-y;
27     if(b<0)
28     {
29         b=-b;
30         a=-a;
31     }
32     exgcd(b,l,x1,y1);
33     if(a%ans!=0)
34         cout<<"Impossible";
35     else
36         cout<<((x1*(a/ans))%(l/ans)+(l/ans))%(l/ans);
37 }

 

原文地址:https://www.cnblogs.com/very-beginning/p/12389345.html