poj 1061 青蛙的约会(扩展欧几里得算法)

来源:互联网 发布:摩托罗拉v8和v9 java 编辑:程序博客网 时间:2024/05/29 19:46

思路:设青蛙跳了k次,那么就有(x+mk)-(y+nk)=p*L.

即x-y+(m-n)k=p*L,即(m-n)*k≡(y-x) (mod L).这个线性同余方程有解当且仅当gcd(m-n,L)|(y-x).

令a=m-n,b=L,c=y-x.用扩展欧几里得解方程ax+by=c.可以求出原方程的一个解.如何求最小正整数解呢?假设我们已经得到一个x0,令d=gcd(m-n,L),那么所有解可以表示为x=x0+k*L/d.设L'=L/d.Xmin=(x0 mod L'+L') mod L'.

推导:若最终要求的方程为:
ax + by = c = k*gcd(a, b)
并设方程
ax1 + by1 = gcd(a, b) 已有解(x1, y1)
两边同时乘上k:
akx1 + bky1 = k*gcd(a, b)
左边作恒等变换
akx1 + bky1 = k*gcd(a, b) <=>
akx1 + bky1 + k1*lcm(a, b) - k1*lcm(a, b) = k*gcd(a, b) <=>
a(kx1 + k1b/gcd(a, b)) + b(ky1 - k1a/gcd(a, b)) = c ...(5)
其中k1为任意整数,lcm为最小公倍数
比较(4) (5)方程可得
x = kx1 + k1b/gcd(a, b)
y = ky1 - k1a/gcd(a, b)
即为最终解。

扩展欧几里得算法:http://www.acmerblog.com/extend-gcd-5610.html

#include <cstdio>#include <cstring>#define ll long longusing namespace std;ll extend_gcd(ll a, ll b, ll &x, ll &y){    if(b == 0)    {        x = 1, y = 0;        return a;    }    else    {        ll r = extend_gcd(b, a%b, y, x);        y -= x*(a/b);        return r;    }}int main(){    ll x, y, m, n, l;    while(~scanf("%I64d%I64d%I64d%I64d%I64d", &x, &y, &m, &n, &l))    {        ll t, p;        ll ans = extend_gcd(n-m, l, t, p);        if((x-y) % ans)            printf("Impossible\n");        else        {            //求最小整数解的算法            t = (x-y)*t/ans;                        //首先令x为一个特解            t = (t % (l/ans)+(l/ans)) % (l/ans);    //再根据公式计算            printf("%I64d\n", t);        }    }}

0 0