POJカエルのデート(拡張ユークリッド)

10111 ワード

カエルのデート
Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 20000/10000K (Java/Other)
Total Submission(s) : 2   Accepted Submission(s) : 2
Problem Description
2匹のカエルがネットで知り合って、楽しく話していたので、一度会う必要があると思っていました.同じ緯度線に住んでいることを喜んで発見し、会うまで西に踊ることを約束した.しかし、彼らは出発する前に重要なことを忘れて、相手の特徴をはっきり聞いていないし、会う具体的な位置を約束していない.しかし、カエルたちは楽観的で、ずっとある方向に飛び降りれば、いつも相手に会えると思っています.しかし、この2匹のカエルが同じ時間に同じ点にジャンプしない限り、永遠に会うことはできません.この2匹の楽観的なカエルを助けるために、この2匹のカエルが会えるかどうか、いつ会えるかを判断するプログラムを書くように要求されました.
この2匹のカエルをそれぞれカエルAとカエルBと呼び,緯度線上の東経0度を原点とし,東から西へを正方向とし,単位長さ1メートルで首尾が接する数軸を得た.カエルAの出発点座標をx、カエルBの出発点座標をyとする.カエルAは一度にmメートル、カエルBは一度にnメートル、2匹のカエルが一度にジャンプするのにかかる時間は同じです.緯度線の総長はLメートルである.今、何回も踊ってから会うように頼んでください.
 
Input
入力には、x≠y<20000000,0 
Output
出会いに必要なジャンプ回数を出力し、永遠に会えない場合は「Impossible」を出力します.
 
Sample Input
1 2 3 4 5
 
Sample Output
4
 
Source
PKU
 
 
詳細:
http://www.cnblogs.com/comeon4mydream/archive/2011/07/18/2109060.html
 
 
http://www.cnblogs.com/jian1573/archive/2012/07/22/2603943.html
 
まず,ユークリッドアルゴリズム(gcd)について議論する.
gcd(a,b)は2つの数の最大公約数を求める
再帰アルゴリズム:
int gcd( int a, int b ) {   return b==0?a:gcd( b, a%b ); //gcd(a,b)=gcd(a%b,b)は,この再帰が1回終了するとa bが減少し続けることが保証されないため,bとa%bを順番に交換する.
非再帰アルゴリズム:
int gcd( int a, int b ) {   if( b==0 )return 0;   while(b)   {     int t=a%b;     a=b;     b=t;   }   return a;
}
ここでアルゴリズムの正しさ、すなわちgcd(a,b)=gcd(b,a%b)を証明することについて議論する.gcd(a,b)=gcd(a,b)=gcd(a−b,b)を証明すればよい.これによりgcd(a,b)==gcd(a−k*b,b)に徐々に拡張できるため、gcd(a−k*b)==gcd(a%b)==gcd(a%b,b)=gcd(a%b,b)に拡張できる.a,bの公約数は必然的にa−b,bの公約数であるため、gcd(a,b)<=gcd(a−b,b);また、a−bの公約数は約数も必然的にa bの公約数,gcd(a,b)>=gcdである.(a-b,b).従ってgcd(a,b)==gcd(a-b,b).
ユークリッドを拡張するには
拡張ユークリッドアルゴリズムは、a*x+b*y=gcd(a,b)のような方程式を解くために用いられる.同様にgcd(a,b)=gcd(b,a%b)を用いてa*x+b*y=gcd(a,b)をb*x'+(a%b)*y'=gcd(b,a%b)に変換する.
再帰的な考え方に基づいて、現在x'y'を求めていると仮定すると、残りの鍵はどのようにx'y'でx y y yを求めるかである.gcd(b,a%b)=b*x'+(a%b)*y'を観察し、右側をa*x+b*yの形式に書き直すだけでよいので、b*x'+(a%b)*y'を変形する必要がある.a%b==a-a/a/b*b*bであるため、b*x'+(a%b)y'=b*x'+(a-a/b*b*b)y'==a*y'+(x*y'+(x*y'==a*y'+(x*y'+(x*y'+'-a/b*y').
これにより、x=y′y=x′−a/b*y′が得られる.
拡張gcdの再帰アルゴリズムは
LL exgcd( LL a, LL b, LL &x, LL &y ) {   LL d, t;   if( b==0 )   {     x=1, y=0;     return a;    }   d=exgcd( b, a%b, x, y );   t=x, x=y, y=t-a/b*y;   return d; //gcd(a,b);}を返す
 方程式の解を得ました
x==x0+b*t;    //    特解+通解
y==y0+a*t;
それから一般的な形式a*x+b*y==cを見ます.
c%gcd(a,b)=0の場合にのみ方程式が解ける.
a*x+b*y=cの解は,まずa*x+b*y=gcd(a,b)を求め,その後x yをc/gcd(a,b)倍に拡大すればよい.
 
#include<iostream>

#include<cstdio>

#include<cstring>



using namespace std;



long long Gcd(long long a,long long b){

    return b==0?a:Gcd(b,a%b);

}



void exGcd(long long a,long long b,long long &x,long long &y){

    if(b==0){

        x=1; y=0;

        return ;

    }

    exGcd(b,a%b,x,y);

    long long tmp=x;

    x=y;

    y=tmp-a/b*y;

}



int main(){



    //freopen("input.txt","r",stdin);



    long long x,y,m,n,L;

    long long a,c,k1,k2,r;

    while(~scanf("%I64d%I64d%I64d%I64d%I64d",&x,&y,&m,&n,&L)){

        a=n-m; c=x-y;

        r=Gcd(a,L);

        if(c%r){

            puts("Impossible");

            continue;

        }

        a/=r; L/=r; c/=r;

        exGcd(a,L,k1,k2);

        long long ans=c*k1-c*k1/L*L;

        if(ans<0)

            ans+=L;

        printf("%I64d
",ans); } return 0; }

 
 
 
#include <stdio.h>

 typedef long long LL;

 LL exgcd( LL a, LL b, LL &x, LL &y )

 {

     LL d, t;

     if( b==0 )

     {

         x=1, y=0;

         return a;    

     }

     d=exgcd( b, a%b, x, y );

     t=x, x=y, y=t-a/b*y;

     return d;

 }

 

 // (a+c*m)%2^k=b ==> c*m-n*2^k=b-a;

 int main( )  

 {  

     LL A,B,C,k, a, b, c, x, y, n;  

     while(scanf("%lld %lld %Illd %lld",&A,&B,&C,&k))  

     {  

         if(!A && !B && !C && !k)  

             break;  

   

         a=C, b=B-A, n=(LL)1<<k;  //2^k   

         LL d=exgcd(a,n,x,y);  // a,n      d=gcd(a,n)   d=ax+by   x、y  

         if(b%d!=0)  //   ax=b(mod n)     

            puts("FOREVER"); 

         else  

         {  

             x=(x*(b/d))%n;  //  ax=b(mod n)      

             x=(x%(n/d)+n/d)%(n/d);  //  ax=b(mod n)        

             printf("%lld
",x); } } return 0; }