洛谷 P1516 青蛙的约会 题解

题目传送门

题目大意: 给一个长度为 L L L 的圆环,有两只青蛙,给出两者的起点和速度,问何时相遇。

题解

显然是个追击问题,先列出柿子:
x + t n ≡ y + t m ( m o d L ) x+tn\equiv y+tm \pmod L x+tny+tm(modL)

其中 t t t 即为我们要求的答案,其他的变量意义如题所述。

那么我们大力变换:
x + t n ≡ y + t m ( m o d L ) x − y + t ( n − m ) ≡ 0 ( m o d L ) \begin{aligned} x+tn&\equiv y+tm \pmod L\\ x-y+t(n-m)&\equiv 0 \pmod L \end{aligned} x+tnxy+t(nm)y+tm(modL)0(modL)

不妨设 A = x − y , B = m − n A=x-y,B=m-n A=xy,B=mn,那么有:
A − t B ≡ 0 ( m o d L ) A-tB\equiv 0 \pmod L AtB0(modL)

这个 ( m o d L ) \pmod L (modL) 有点棘手,不妨设多一个 k L kL kL 带进去,有
A − t B = k L k L + t B = A \begin{aligned} A-tB&= kL\\ kL+tB&=A \end{aligned} AtBkL+tB=kL=A

根据裴蜀定理,如果 A A A 不是 ( L , B ) (L,B) (L,B) 的倍数,那么该方程无解,此时输出 ′ ′ I m p o s s i b l e ′ ′ ''Impossible'' Impossible

如果有解,还要注意, B B B 不能是负数,所以如果 B B B 是负数的话就要将 A , B A,B A,B 同时取反,这是不影响答案的。(回到 A − t B ≡ 0 ( m o d L ) A-tB\equiv 0 \pmod L AtB0(modL) 这个柿子就能明白)

那么我们可以用 e x g c d exgcd exgcd 求出下面这个方程的一组合法解:
k L + t B = gcd ⁡ ( L , B ) kL+tB=\gcd(L,B) kL+tB=gcd(L,B)

对于求出来的一组合法的解 k 1 , t 1 k_1,t_1 k1,t1,并不一定是最后的答案,我们要的是最小的 t 1 t_1 t1,所以我们还得搞一搞。

g = gcd ⁡ ( L , B ) g=\gcd(L,B) g=gcd(L,B),我们发现,让 t 1 t_1 t1 L g \frac L g gL 再让 k 1 k_1 k1 B g \frac B g gB,这样又能得到一组另外的合法的解,那么我们不妨让 t 1 t_1 t1 L g \frac L g gL 取模,那么就能得到最小解了。

但是我们求出的是 k L + t B = gcd ⁡ ( L , B ) kL+tB=\gcd(L,B) kL+tB=gcd(L,B) 这个方程的最小解,要让整个方程乘以 A gcd ⁡ ( L , B ) \frac A {\gcd(L,B)} gcd(L,B)A,才能得到原方程的最小解。(注意这个解也需要对 L g \frac L g gL 取模)

于是代码如下:

#include <cstdio>
#include <cstring>
#define ll long long

ll x,y,n,m,L;
ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);}
void exgcd(ll a,ll b,ll &xx,ll &yy)
{
	if(b==0){xx=1;yy=0;return;}
	exgcd(b,a%b,yy,xx);
	yy-=a/b*xx;
}

int main()
{
	scanf("%lld %lld %lld %lld %lld",&x,&y,&n,&m,&L);
	ll A=x-y,B=m-n,k,t,g;
	if(B<0)A=-A,B=-B;
	g=gcd(L,B);//注意,要在B判负之后再求gcd
	if(A%g!=0)return printf("Impossible"),0;
	exgcd(L,B,k,t);
	t*=A/g;
	t=(t%(L/g)+L/g)%(L/g);//注意负数的情况
	printf("%lld",t);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值