扩展欧几里得算法:对于不完全为0的非负整数n,m,gcd(n,m)表示n,m的最大公约数,必然存在整数n,m使得gcd(n,m)=nx+my。
假设n>m,当m=0时,gcd(n,m)=n,这个时候x=1,y=0;
其他情况:设n*x1+m*y1=gcd(n,m),m*x2+(n mod m)*y2=gcd(m,n%m);由欧几里得算法有:gcd(n,m)=gcd(m,n%m);
则有:n*x1+m*y1 = m*x2+(n mod m)*y2 = m*x1+(n-(n/m)*m)*y2 = m*y2+n*y2-(n/m)*m*y2,所以:x1=y2,y1=x2-(n/m)*y2。扩展欧几里得的模板为:
#define __int64 long long
__int64 ExGcd(__int64 n,__int64 m,__int64 &x,__int64 &y)//nx+my=gcd(n,m);
{ if(m==0) {x=1,y=0;return n;}//返回的是n,m的最大公约数
__int64 value=ExGcd(m,n%m,x,y);
__int64 temp=x;
x=y,y=temp-(n/m)*y;
return value;
}
定理1:对于方程a*x+b*y=n,有整数解的充分必要条件是:n%gcd(a,b)==0。
例题1:POJ 1061(青蛙的约会)
假设经过t分钟后能够相遇,那么他们走的距离之差一定是总长度的倍数。那么则有:(a*t+dx)-(b*t+dy)=L*num(其中num为总长度倍数)。所以有:(b-a)*t+L*num=dx-dy。那么
就相当于:nx+my=gcd(n,m)的类型了。也就是说这个方程要有整数解(t,num为未知数),为扩展欧几里得算法。
所以说这个方程要有整数解的话,b-a和L的最大公约数为:dx-dy,即:(dx-dy)%gcd(b-a,L)=0;当不满足这个条件时输出:"Impossible"。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define __int64 long long
__int64 dx,dy,a,b,L,x,y;
__int64 ExGcd(__int64 n,__int64 m,__int64 &x,__int64 &y)
{ if (m==0) { x=1,y=0; return n; }
__int64 temp,val=ExGcd(m,n%m,x,y);
temp=x,x=y,y=temp-(n/m)*y;
return val;
}
int main()
{ while(scanf("%lld%lld%lld%lld%lld",&dx,&dy,&a,&b,&L)!=EOF)
{ __int64 val=ExGcd(b-a,L,x,y);
L/=val;
if((dx-dy)%val) puts("Impossible");
else printf("%lld\n",((dx-dy)/val*x%L+L)%L);
}
return 0;
}