poj1061青蛙的約會

青蛙的約會
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 88953   Accepted: 15844

Description

兩隻青蛙在網上相識了,它們聊得很開心,於是覺得很有必要見一面。它們很高興地發現它們住在同一條緯度線上,於是它們約定各自朝西跳,直到碰面爲止。可是它們出發之前忘記了一件很重要的事情,既沒有問清楚對方的特徵,也沒有約定見面的具體位置。不過青蛙們都是很樂觀的,它們覺得只要一直朝着某個方向跳下去,總能碰到對方的。但是除非這兩隻青蛙在同一時間跳到同一點上,不然是永遠都不可能碰面的。爲了幫助這兩隻樂觀的青蛙,你被要求寫一個程序來判斷這兩隻青蛙是否能夠碰面,會在什麼時候碰面。 
我們把這兩隻青蛙分別叫做青蛙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位置,母青蛙在y位置。公青蛙每次跳m米,母青蛙每次跳n米,並且都是向右跳的。地球經線長度是L,然後地球是圓的,也就是說,跳到L、L+1、L+2……其實就是跳到0、1、2。 公青蛙想追母青蛙,問多少次後它們能跳到一起。如果它們永遠不能相遇,就輸出Impossible(好可憐啊!) 

很明顯嘛,就是求一個k,使x + k*m ≡ y + k*n (mod L) 嘛,木有錯吧?至少我是這麼想滴!然後對方程化簡咯,就變成(n-m) * k ≡ x-y (mod L)咯。然後這個方程其實就等價於(n-m)*k + L*s = x-y咯。這就是ax + by = c求整數x的模型。

要求ax + by = c的整數x解,可不是那麼簡單滴,首先,設d = gcd(a, b),方程兩邊除以d得到a/d * x + b/d * y = c/d,很顯然嘛,a是整除d的,b也是整除d的,而x、y都是整數解,所以要求c/d也是整數嘛。如果c不整除d,當然就是Impossible咯。不然的話,如果我們能求出ax0+by0=d的解x0和y0,那麼兩邊乘以c/d即a(c/d * x0) + b(c/d * y0) = c,就可以得到原來方程的解x = (c/d * x0),y = (c/d * y0)咯。

ax0 + by0 = d一定有解?這就得通過嚴謹的證明了:

定理一:如果d = gcd(a, b),則必能找到正的或負的整數k和l,使d = a*k + b*l。

證明:由於 gcd(a, 0) = a,我們可假設b ≠ 0,這樣通過連除我們能夠寫出

a = b*q1 + r1

b = r1*q2 + r2

r1 = r2*q3 + r3

……

 由第一式有r1 = a - q1*b,所以r1能寫成k1*a + l1*b的形式(這時k1 = 1, l1 = -q1)。由第二式有r2 = b - r1*q2 = b - (k1*a + l1*b)*q2 = -q2*k1*a + (1 - q2*l1)*b = k2*a + l2*b。

顯然,這過程通過這一串餘數可重複下去,直到得到一個表達式rn = k*a + l*b,也就是d = k*a + l*b,這就是我們所要證明的。

所以說,ax0 + by0 = d一定有解!那麼應該怎麼求x0和y0呢?要用到一種叫做擴展歐基裏得的算法(NND,第一次聽說,我還是太弱了啊~~~)!

求法如下:由於gcd(a, b) = gcd(b, a%b) (這個不用證明了吧???地球人都知道!),有ax0 + by0 = gcd(a, b) = gcd(b, a%b) = bx1 + (a%b)y1,而a%b又可以寫成a-a/b*b(a/b*b不等於a啊!),所以=bx1 + (a-a/b*b)y1 = ay1 + b(x1-a/b*y1),所以如果我們求出gcd(b, a%b) = bx1 + (a%b)y1的x1和y1,那麼通過觀察就可以求出x0 = y1,y0 = (x1 - a/b*y1)。那我們怎樣求x1和y1呢?當然是求x2和y2了,做法一樣滴。一直求到gcd(an, 0) = an*xn + 0 * yn,這時令xn=1,yn=0就完事了,就可以求xn-1和yn-1,然後xn-2和yn-2,然後一直求到x0和y0了。

所以得到ax0 + by0 = gcd(a, b)求整數x0、y0的擴展歐基裏得算法

然後求ax + by = c,判斷c如果不能被d整除就Impossible,否則就令x = c/d * x0就可以得到一個x解了。

但有無數個解滿足ax + by = c的。爲神馬呢?ax + by = c其實就等價於ax ≡ c (mod b)對不?如果我得到一個特解x*,那麼加上若干倍b還是這個方程的解,因爲a(x*+k*b) = ax* + a*k*b ≡ c + 0 ≡ c (mod b)。因而方程在[0, b-1]上一定有整數解(假如小於0,你加上若干倍b啊,就可以讓它保持在0~b-1中;如果大於b-1,你減去若干倍b啊,它也保持0~b-1)。

那麼怎樣求最小的非負整數x呢?又要用到兩個定理:

定理二:若gcd(a, b) = 1,則方程ax ≡ c (mod b)在[0, b-1]上有唯一解。

證明:由定理一知,總可以找到或正或負的整數k和l使a*k + b*l = gcd(a, b) = 1,即我們可以求出ax ≡ 1 (mod b)的解x0。當然,兩邊乘以c有a(cx0) ≡ c (mod b),所以有x = cx0就是ax ≡ c (mod b)的解。由於加上或減去若干倍b都是該方程的解,所以x在[0, b-1]上有解。那麼怎樣確定它的唯一性呢?我花了一個小時終於證明出來了,證明方法就是,假設x1和x2都是[0, b-1]上的解,那麼就有ax1 ≡ c (mod b),ax2 ≡ c (mod b),兩式相減就有a(x1-x2) ≡ 0 (mod b),即a(x1-x2)可以被b整除。但gcd(a, b) = 1啊!所以a和b之間沒有共同的語言可以交流,所以只能說(x1-x2)被b整除了。但x1和x2都在[0, b-1]上,所以x1-x2也在[0, b-1]上,所以只能說x1-x2=0了,因此x1=x2。這就證明了解的唯一性!

這個定理不過是爲了證明定理三方便而已,定理三才是王道:

定理三:若gcd(a, b) = d,則方程ax ≡ c (mod b)在[0, b/d - 1]上有唯一解。

證明:上面說過,這個該死的方程等價於ax + by = c,如果有解,兩邊同除以d,就有a/d * x + b/d * y = c/d,即a/d * x ≡ c/d (mod b/d),顯然gcd(a/d, b/d) = 1,所以由定理二知道x在[0, b/d - 1]上有唯一解。所以ax + by = c的x在[0, b/d - 1]上有唯一解,即ax ≡ c (mod b)在[0, b/d - 1]上有唯一解,得證!

有了上面幾個該死的定理,小菜我終於把最小非負整數的問題解決了。如果得到ax ≡ c (mod b)的某一特解X,那麼我令r = b/gcd(a, b),可知x在[0, r-1]上有唯一解,所以我用x = (X % r + r) % r就可以求出最小非負整數解x了!(X % r可能是負值,此時保持在[-(r-1), 0]內,正值則保持在[0, r-1]內。加上r就保持在[1, 2r - 1]內,所以再模一下r就在[0, r-1]內了)。

代碼如下:

#include <iostream>
using namespace std;
long long extgcd(long long a, long long b, long long &x, long long &y)
{
    long long d, t;
    if (b == 0) { x = 1; y = 0; return a; }
    d = extgcd(b, a % b, x, y);
    t = x - a / b * y; x = y; y = t;
    return d;
}
int main()
{
    long long x, y, m, n, L, X, Y, d, r;
    while (cin >> x >> y >> m >> n >> L)
    {
        d = extgcd(n - m, L, X, Y); r = L / d;
        if ((x - y) % d) cout << "Impossible" << endl;
        else cout << ((x - y) / d * X % r + r) % r << endl;
    }
    return 0;
}


發佈了55 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章