P1516 青蛙的约会 [exgcd]

P1516 青蛙的约会

题意:在一个长为\(l\)的环上面有两只青蛙,一只出发点为\(x\),一次跳\(m\),另一只出发点为\(y\),一次跳\(n\),求相遇时间。

这个长为\(l\)的环不难想到了以\(l\)为模的同余。其实就是求这个\(t\)\(x+t\times m \equiv y + t \times n\pmod l\)

把这个变成普通式子:\(x - y + t(m - n) = k \times l\)

整理一下:\(t \times (m-n) - k \times l = y - x\)

这是一个二元不定方程,也就很自然地想到了另一个式子:\(t' \times (m-n) - k' \times l = gcd(m - n, l)\)

用肥鼠定理可以判断无解。套exgcd模板可以求出\(t'\)\(k'\)

上面两个式子如果有解的话一定是倍数关系的,所以有这么一个式子:\(\frac{gcd(m-n,l)}{y-x} = \frac{t'}{t}\),即\(t=\frac{t'(y-x)}{gcd(m-n,l)}\)

但是\(t\)可能是负数,我们需要调整\(t\)为最小正整数解。

使用exgcd的通解公式:\(x=x_0+k\times \frac{b}{gcd(a,b)}\)。把里面的式子换成这道题的就行了。

有个需要注意的:

\(gcd\)是不支持负数的,所以这个\(y-x\)要确保为正,当这个\(y-x\)为负时,同时给\(m-n\)\(y-x\)添负号。

代码:

#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
#define ll long long

ll exgcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {
        x = 1; y = 0; return a;
    } else {
        ll ret = exgcd(b, a % b, x, y);
        ll t = x;
        x = y;
        y = t - a / b * y;
        return ret;
    }
}
int main() {
    ll x, y, m, n, l; cin >> x >> y >> m >> n >> l;
    // x + m * t === y + n * t (mod l)
    // x - y + t * (m - n) = k * l
    // t * (m - n) - k * l = y - x
    ll A = m - n, B = l, C = y - x;
    if(A < 0) {
        A = -A; C = -C;
    }
    ll g = exgcd(A, B, x, y);
    if(C % g) {
        cout << "Impossible" << endl;
        return 0;
    }
    x = x * C / g;
    // C : g = t : x
    ll bg = B / g;
    if(bg < 0) bg = -bg;
    x = (x % bg + bg) % bg;
    cout << x << endl;
    return 0;
}

转载于:https://www.cnblogs.com/Garen-Wang/p/10403366.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值