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

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

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

\[(m-n)\times x\equiv m1-n1\pmod{l} \]

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

\[(m-n)\times x+l\times y=m1-n1 \]

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

不妨设\(a=m-n,b=l,c=m1-n1\)

那么原方程就是:

\[a\times x+b\times y=c \]

然后我们知道一个性质:

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

所以说我们先判断方程是否有解,若无解就输出\(\mathbf{Impossible}\)

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

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

那么有:

\(a\times(c\div gcd(a,b))\times x+b\times(c\div gcd(a,b))\times y=c\)

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

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

\(p\times x+q\times y=c\)

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

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

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

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

\[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)} \]

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

\[((x \bmod g)+g)\bmod g \]

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

代码流程梳理一下:

flowchat st=>start: 开始 e=>end: 结束 op=>operation: 求出gcd(a,b) op2=>operation: 输出"Impossible" op3=>operation: 求出exgcd(a,b) op4=>operation: x*=c/gcd(a,b),y*=c/gcd(a,b) op5=>operation: 求出g op6=>operation: 求出x的最小正整数解,输出 cond=>condition: gcd(a,b)是否整除c? st->op->cond op3->op4->op5->op6->e cond(yes)->op3 cond(no)->op2

最后代码如下:

#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;
}
posted @ 2022-10-29 11:23  ez_lcw  阅读(18)  评论(0编辑  收藏  举报