贴一个题目地址吧:http://poj.org/problem?id=1061
(下文对扩展欧几里得算法的论述基本取决于所打的代码模板,故不准确)
抽象题意。设青蛙跳过的圈数为K,青蛙跳的次数为T。
根据题意有X+MT ≡ Y+NT(mod L)==> LK+(N-M)*T=X-Y
那么问题就变成求解上述方程的最小非负整数T解。
方程中N-M和X-Y可能为负,K与T为方程的不定参数,故LK+(N-M)*T可以表示L,N-M的线性组合。
那么可以应用扩展欧几里得算法求出 LK + (N-M)*T = O的一组解(K0,T0)和O。
这里O比较特殊,O的绝对值和L,N-M的线性组合的绝对值的最小值相等,其实也就是L,M-N的最大公约数的绝对值,这是由扩展欧几里得算法的特性决定的。
故L,N-M的所有线性组合都可以用O乘以任意整数表示,也就是O是L,M-N的任意线性组合的因子。
容易得出如果X-Y不能被O整除,那么方程LK + (N-M)*T = X-Y无解,输出impossible。
将上面的方程乘以V=((X-Y)/O)得到LK+(N-M)*T=X-Y的一组特解(K1=K0*V, T1=T0*V),但题目要求T为最小非负整数。
注意O为L,M-N的最大公约数,设得通解K=K1+(N-M)/O*U,T=T1+L/O*U。其中U为任意整数,代入原方程可行。
故得到T的通解,最后求通解中T的最小非负值即可。
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
inline ll ABS(ll a) { return a>0?a:-a; }
ll extgcd(ll a,ll b,ll &x,ll &y)
{
ll d=a;
if(b!=0)
{
d=extgcd(b,a%b,y,x);
y-=(a/b)*x;
}
else {x=1; y=0;}
return d;
}
int main()
{
ll x,y,m,n,L;
while(~scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L))
{
ll t,k,c=x-y;
ll d=extgcd(L,n-m,k,t);
if(c%d!=0)
{
printf("Impossible\n");
continue;
}
ll v=c/d;
k*=v,t*=v;
ll ppp=ABS(L/d);
if(t<0)
{
while(t<0) t+=ppp;
}
else if(t>0)
{
while(t-ppp>0) t-=ppp;
}
printf("%lld\n",t);;
}
}
形如p * a+q * b = c的方程
p1,q1为已知特解。
有p = p1 + b/Gcd(a, b) * t