拓展欧几里得算法|青蛙的约会【拓展欧几里得算法】【详细思路以及推导过程】【萌新必会系列】

在上这道题之前,先给大家看个精彩的:
拓展欧几里得算法|青蛙的约会【拓展欧几里得算法】【详细思路以及推导过程】【萌新必会系列】
文章图片


这道玄学的题目,让我整整花费了八个小时去推导以及去了解拓展欧几里得,从一个萌新到真正可以理清自己的思路了。

两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
Input 输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。 Output 输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible" Sample Input

1 2 3 4 5

Sample Output
4


这是学长挂给我们的一道题,重在让我们理清欧几里得算法的作用以及灵活运用它。

思路:遇上这道题,我们先列写出方程,我们可以知道:x+m*t-y-n*t=p*L(p为转了几圈)。
很显然,这是一道拓展欧几里得算法,然后我们针对这道题开始讲解什么是欧几里得算法:
假如存在这样的a*x+b*y=d的线性方程,我们想知道它的通解怎样实现,那么我们就举个例子吧:

a*x+b*y=d,如果d mod gcd(a, b)==0

则,a*x1+b*y1=d; b*x2+a%b*y2=d; 整理得b*x2+(a-(a/b)*b)*y2=d;

于是一一对应前式a、b所对应点有,x1=y2; y1=x2-(a/b)*y2。

那么,我们由此可以写出拓展欧几里得公式:
ll exgcd(ll a, ll b, ll &x, ll &y) { if(b==0) { x=1; y=0; return a; } ll g=exgcd(b, a%b, x, y); ll temp=x; x=y; y=temp-y*(a/b); return g; }


当然,这是一种四个参数的,还有种五个参数的:
void exgcd(ll a, ll b, ll &d, ll &x, ll &y) { if(b==0) { d=a; x=1; y=0; return; } exgcd(b, a%b, d, y, x); y-=a/b*x; }


现在,我们要做一个判断:方程是否有解?

拓展欧几里得公式存在,就是指a*x+b*y=d;而d%gcd(a, b)==0,那么假如d%gcd(a, b)!=0,则等式不成立。

判断条件:
if(d%gcd(a, b)!=0) 不存在解。
寻找结果answer:

直接输出 exgcd(a, b, &x, &y)中的x?当然是不行的,我们求得的x为其中的一个特解,不一定是最佳的答案,而且还有负值的可能,所以我们要做些处理:

对于一个x数取到0~r中的值,我们可以这么操作:x=((x%r)+r)%r。
那么容我证明一下这个r的取值:
a*x0+b*y0=d; 又假设还存在这样的x1、y1:a*x1+b*y1=d;

则,a*(x1-x0)=b*(y0-y1); a/gcd(a, b)*(x1-x0)=b/gcd(a, b)*(y0-y1);

a/gcd(a, b)与b/gcd(a, b)互质,则(x1-x0)与b/gcd(a, b)成正比,(y0-y1)与a/gcd(a, b)成正比
所以能得到:x=x0+K*b/gcd(a, b)其中K为一切整数,y=y0+K*a/gcd(a, b)其中K为一切整数。
那么,对于x而言,r=b/gcd(a, b)。
ll want(ll x0, ll r0) { return ((x0%r0)+r0)%r0; }


捋通了思路之后,我们就可以知道了:我们对于公式:(n-m)*t+L*P=x-y;分别将他们看作线性方程的a,b,x,y,即可求得正解。
【拓展欧几里得算法|青蛙的约会【拓展欧几里得算法】【详细思路以及推导过程】【萌新必会系列】】完整代码:
#include #include #include #include #include using namespace std; typedef long long ll; ll gcd(ll a, ll b) { if(b==0)return a; return gcd(b, a%b); } ll x,y,m,n,L; ll exgcd(ll a, ll b, ll &x, ll &y) { if(b==0) { x=1; y=0; return a; } ll g=exgcd(b, a%b, x, y); ll temp=x; x=y; y=temp-y*(a/b); return g; } ll want(ll x0, ll r0) { return ((x0%r0)+r0)%r0; } int main() { while(scanf("%lld %lld %lld %lld %lld",&x,&y,&m,&n,&L)!=EOF) { ll t,p; ll a1,b1,d1; d1=x-y; b1=L; a1=n-m; ll k=gcd(a1, b1); if(d1%k!=0) { printf("Impossible\n"); continue; } exgcd(a1, b1, t, p); ll r=b1/gcd(a1, b1); printf("%lld\n",want(t*d1/k, r)); } return 0; }


    推荐阅读