1. 程式人生 > >數論 青蛙的約會 擴展歐幾裏得

數論 青蛙的約會 擴展歐幾裏得

包括 ring each res 自己 歐幾裏得 The define 線上

 

R - 青蛙的約會

兩只青蛙在網上相識了,它們聊得很開心,於是覺得很有必要見一面。它們很高興地發現它們住在同一條緯度線上,於是它們約定各自朝西跳,直到碰面為止。可是它們出發之前忘記了一件很重要的事情,既沒有問清楚對方的特征,也沒有約定見面的具體位置。不過青蛙們都是很樂觀的,它們覺得只要一直朝著某個方向跳下去,總能碰到對方的。但是除非這兩只青蛙在同一時間跳到同一點上,不然是永遠都不可能碰面的。為了幫助這兩只樂觀的青蛙,你被要求寫一個程序來判斷這兩只青蛙是否能夠碰面,會在什麽時候碰面。
我們把這兩只青蛙分別叫做青蛙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






這個題目是一個擴展歐幾裏得,一開始還沒有看出來,自己的公式列錯了,後來看出來之後,取模又沒有取好,不過現在都解決了,
接下來我說一下這個題目的具體解題過程吧。
這個開始可以推得公式 n*t+y=x+m*t (mod l) 所以就可以化簡成 (n-m)*t≡ x-y (mod l)

然後我們令a=n-m b=x-y
所以就可以轉化成 a*t=b mod l
這個就是擴展歐幾裏得的求解 線性同余方程 的應用 這個不明白的可以看這個博客:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html
接下來說說線性同余方程過程

a*x≡b mod n
這個可以轉化成 a*x+n*y=b (因為y不是需要得到的值,所以無所謂正負,不然這個應該是 a*x=n*y+b 換過去應該是有個負號的
然後你就會發現這個與擴展歐幾裏得的式子很像:a*x+n*y=gcd(a,n)
所以上面式子要求x,和下面式子求x,y差不多。
已知:如果一個方程a*x+b*y=c 如果gcd(a,b)|c 那麽這個方程則有整數解,反之則沒有。

所以我們要求整數解,那麽說明gcd(a,n)|b 如果不整除,則說明輸出Impossible
然後就很簡單了,我們求出 擴展歐幾裏得的解,然後 就可以得到上式的解為 ans=x*b/gcd(a,n)
這個只是一個解,不一定是最小的正整數解,那麽該如何取這個最小的正整數解呢?

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

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

這個是兩個定理,具體證明過程請參照:

http://www.cnblogs.com/comeon4mydream/archive/2011/07/18/2109060.html

由定理二可得,0~n-1上有唯一的解,但是這個又有點特別,因為這個的n值擴大了,需要縮小

縮小之後的結果就是在0~n/d-1 上有唯一的解,這個證明過程可以參照定理二的證明過程





#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const ll maxn = 3e10;
ll exgcd(ll a,ll b,ll&x,ll&y)
{
    if(b==0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll ans = exgcd(b, a%b, x, y);
    ll tmp = x;
    x = y;
    y = tmp - a / b * y;
    return ans;
}


int main()
{
    ll x, y, m, n, l,s1,s2;
    cin >> x >> y >> m >> n >> l;
    ll a = n - m, b = x - y;
    ll d = exgcd(a, l,s1,s2);
    ll p = l / d;
    if(b%d!=0)
    {
        printf("Impossible\n");
        return 0;
    }
    ll ans = (s1 * (b / d) % p+p)%p;
    printf("%lld\n", ans);
    return 0;
}







然後再補充一個題:
S - C Looooops
A Compiler Mystery: We are given a C-language style for loop of type
for (variable = A; variable != B; variable += C)

statement;

I.e., a loop which starts by setting variable to value A and while variable is not equal to B, repeats statement followed by increasing the variable by C. We want to know how many times does the statement get executed for particular values of A, B and C, assuming that all arithmetics is calculated in a k-bit unsigned integer type (with values 0 <= x < 2 k) modulo 2 k.

Input
The input consists of several instances. Each instance is described by a single line with four integers A, B, C, k separated by a single space. The integer k (1 <= k <= 32) is the number of bits of the control variable of the loop and A, B, C (0 <= A, B, C < 2 k) are the parameters of the loop.

The input is finished by a line containing four zeros.
Output
The output consists of several lines corresponding to the instances on the input. The i-th line contains either the number of executions of the statement in the i-th instance (a single integer number) or the word FOREVER if the loop does not terminate.
Sample Input
3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0
Sample Output
0
2
32766
FOREVER





這個題目和上面的一樣的,所以就不說了,當作練習題練練手。






數論 青蛙的約會 擴展歐幾裏得