您的位置:首页 > 其它

PKU1061 解题报告 青蛙的约会 __用扩展欧几里得解模同余方程

2009-08-07 18:43 344 查看
题目描述:



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

输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。



输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行"Impossible"

Sample Input:

1 2 3 4 5

Sample Output:

4



题目分析:

根据题意可知,题目要求的是求(x+k*m)mod l=(y+k*n)mod l这个模方程的k的最小整数解;跟据模的性质对这个方程变形得:k*(m-n)+t*l=y-x(t为引进的一整数);

令a=(m-n);b=y-x;得:

k*a+t*l=b; 0)

看到这个式子是不是感觉很眼熟,对,它就是扩展欧几里得法能解的标准方程a*x+b*y=d(此a,b非彼a,b)的标准形;唯一的不同是扩展欧几里得d是前面两系数a,b的最大公约数;而0)式中的b就不能保证了。

不过没关系,先用扩展欧几里得得出k*a+t*l=gcd(a,l)的一个解k0,t0;再观察两个式子:

k*a+t*l=b 0)

k0*a+t0*l=d 1)(令d=gcd(a,l));

将0)式两边都除以d,得:

k*(a/d)+t*(l/d)=b/d;

因为d为a,b的最大公约数,所以a/d,l/d为整数,所以b/d必定为整数,否则方程无解;

将1)式两边都乘以b/d与0)式比较:

k*a+t*l=b 0)

(k0*b/d)*a+t0*(b/d)*l=b 1)

得k=k0*b/d;t=t0*b/d;

接下来就是由一个解扩展成一个解系:

1)除以b得: k0*(a/d)+t0*(l/d)=1;

因为(a/d)和(l/d)互质,将方程写成:

(k0+u*(l/d))*(a/d)+(t0+v*(a/d))*(l/d)=1;

只要u*(l/d)*(a/d)+v*(a/d)*(l/d)=0成立就行;

所以k,t的解系可以写成k=(k0+u*(l/d))*(b/d);t=(t0+v*(a/d))*b/d;

接下来就是求k的最小整数解了;

因为k=(k0 mod (l/d)+(u+k0/(l/d))*(l/d))*(b/d);

所以kmin=(k0*(b/d)) mod (l/d);



大功基本高成了,还差最后一步,那就是如何用扩展欧几里得解k*a+t*l=gcd(a,l):

对于a*x+b*y=d;
递归调用时
令a=b;b=a%b;
将其变为形式2) b*x+a%b*y=d;
变形:b*x+a*y-(a/b)*b*y=d;
再变:a*y+b(x-a/b*y)=d; 3)

与2)式比较:b*x+a%b*y=d; 2)
得:
当a=b;b=a%b时:x=y;y=x-a/b*y;

调用过程中的x,y就是对应的a,b的解;
当回到顶层时,a,b就是最初的a,b所以此时的x,y就是所求解;
函数写法如下:(解保存在全局变量k,t中)
__int64 extended_gcd(__int64 a,__int64 b)
{
if (b==0)
{
k=1;
t=0;
d=a;
return a;

}
else
{
__int64 tp_gcd;
tp_gcd=extended_gcd(b,a%b);
__int64 temp;
temp=k;
k=t;
t=temp-(a/b)*t;
return tp_gcd;
}
}
附上AC代码:
#include<stdio.h>
__int64 k,t,d;
__int64 extended_gcd(__int64 a,__int64 b)
{
if (b==0)
{
k=1;
t=0;
d=a;
return a;

}
else
{
__int64 tp_gcd;
tp_gcd=extended_gcd(b,a%b);
__int64 temp;
temp=k;
k=t;
t=temp-(a/b)*t;
return tp_gcd;
}
}

int main()
{
__int64 x,y,m,n,a,b,aa,ll,l;
while(scanf("%I64d %I64d %I64d %I64d %I64d",&x,&y,&m,&n,&l)!=EOF)
{
a=m-n;b=y-x;
if (a<0) {a=-a;b=-b;}
extended_gcd(a,l);
if (b%d!=0) printf("Impossible/n");
else
{
k=k*b/d;
t=t*b/d;
l=l/d;
if (k>=0)
k=k%l;
else k=k%l+l;
printf("%I64d/n",k);
}

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: