【poj1061】青蛙的约会(扩展欧几里得)

不妨设青蛙A的出发点坐标是 m 1 m1 m1,青蛙B的出发点坐标是 n 1 n1 n1。青蛙A一次能跳 m m m米,青蛙B一次能跳 n n n米,跳一圈长 l l l米,设青蛙A、B跳了 x x x次。

那么题目要求的是满足下面这个柿子最小 x x x正整数解:

( m − n ) × x ≡ m 1 − n 1 ( m o d l ) (m-n)\times x\equiv m1-n1\pmod{l} (mn)×xm1n1(modl)

不妨把这个不定方程变形一下:

( m − n ) × x + l × y = m 1 − n 1 (m-n)\times x+l\times y=m1-n1 (mn)×x+l×y=m1n1

看到这个形式,就想到用扩展欧几里得来求解。

不妨设 a = m − n , b = l , c = m 1 − n 1 a=m-n,b=l,c=m1-n1 a=mn,b=l,c=m1n1

那么原方程就是:

a × x + b × y = c a\times x+b\times y=c a×x+b×y=c

然后我们知道一个性质:

a × x + b × y = c a\times x+b\times y=c a×x+b×y=c有解,则满足 g c d ( a , b ) ∣ c gcd(a,b)|c gcd(a,b)c

所以说我们先判断方程是否有解,若无解就输出 I m p o s s i b l e \mathbf{Impossible} Impossible

然后如果有解,我们就先用扩展欧几里得求出 a × x + b × y = g c d ( a , b ) a\times x+b\times y=gcd(a,b) a×x+b×y=gcd(a,b)的一组解。

然后我们对这个方程左右两边同时乘上 c ÷ g c d ( a , b ) c\div gcd(a,b) c÷gcd(a,b)

那么有:

a × ( c ÷ g c d ( a , b ) ) × x + b × ( c ÷ g c d ( a , b ) ) × y = c a\times(c\div gcd(a,b))\times x+b\times(c\div gcd(a,b))\times y=c a×(c÷gcd(a,b))×x+b×(c÷gcd(a,b))×y=c

为了方便起见,我们这里令 p = a × ( c ÷ g c d ( a , b ) ) p=a\times(c\div gcd(a,b)) p=a×(c÷gcd(a,b)) q = b × ( c ÷ g c d ( a , b ) ) q=b\times(c\div gcd(a,b)) q=b×(c÷gcd(a,b))

这时,我们就可以求出满足下列方程的一组特解:

p × x + q × y = c p\times x+q\times y=c p×x+q×y=c

此时,我们发现 x x x可以任意变为 ( x + k × q g c d ( p , q ) ) (x+k\times \frac{q}{gcd(p,q)}) (x+k×gcd(p,q)q),且总有对应的一个整数解 y y y使得原方程依旧成立,因为:

p × x + q × y = c p\times x+q\times y=c p×x+q×y=c成立,则必有 p × ( x + q g c d ( p , q ) ) + q × ( y − p g c d ( p , q ) ) = c p\times (x+\frac{q}{gcd(p,q)})+q\times (y-\frac{p}{gcd(p,q)})=c p×(x+gcd(p,q)q)+q×(ygcd(p,q)p)=c 成立。

(为什么一定要除 g c d ( p , q ) gcd(p,q) gcd(p,q)?因为在电脑中会向下取整,而且我们要使得 q g c d ( p , q ) \frac{q}{gcd(p,q)} gcd(p,q)q尽量小,这样才能找到更多的 x x x解)。

所以令 g = q g c d ( p , q ) g=\frac{q}{gcd(p,q)} g=gcd(p,q)q,即:

g = q g c d ( p , q ) = b × ( c ÷ g c d ( a , b ) ) g c d ( a × ( c ÷ g c d ( a , b ) ) , b × ( c ÷ g c d ( a , b ) ) ) = q g c d ( a , b ) g=\frac{q}{gcd(p,q)}=\frac{b\times(c\div gcd(a,b))}{gcd(a\times(c\div gcd(a,b)),b\times(c\div gcd(a,b)))}=\frac{q}{gcd(a,b)} g=gcd(p,q)q=gcd(a×(c÷gcd(a,b)),b×(c÷gcd(a,b)))b×(c÷gcd(a,b))=gcd(a,b)q

那么 x x x的最小正整数解为:

( ( x   m o d   g ) + g )   m o d   g ((x \bmod g)+g)\bmod g ((xmodg)+g)modg

那么我们就可以输出答案了。

代码流程梳理一下:

Created with Raphaël 2.2.0 开始 求出gcd(a,b) gcd(a,b)是否整除c? 求出exgcd(a,b) x*=c/gcd(a,b),y*=c/gcd(a,b) 求出g 求出x的最小正整数解,输出 结束 输出"Impossible" yes no

最后代码如下:

#include<bits/stdc++.h>
 
#define ll long long
 
using namespace std;
 
ll m1,n1,m,n,l;
 
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1ll,y=0ll;
        return a;
    }
    ll ans=exgcd(b,a%b,x,y);
    ll xx=x;
    x=y;
    y=xx-(a/b)*y;
    return ans;
}
 
int main()
{
    while(~scanf("%lld%lld%lld%lld%lld",&m1,&n1,&m,&n,&l))
    {
        if(n<m)
        {
            swap(n,m);
            swap(n1,m1);
        }
        ll a=n-m,b=l,c=m1-n1,x,y;
        ll t=exgcd(a,b,x,y);
        if(c%t)
        {
            puts("Impossible");
            continue;
        }
        c/=t;
        x*=c;
        ll mod=b/t;
        x=(x%mod+mod)%mod;
        printf("%lld\n",x);
    }
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值