见:P1516 青蛙的约会 - 洛谷
想进步的进来~
题目描述
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙 A 和青蛙 B,并且规定纬度线上东经 0 度处为原点,由东往西为正方向,单位长度 1 米,这样我们就得到了一条首尾相接的数轴。设青蛙 A 的出发点坐标是 x,青蛙 B 的出发点坐标是 y。青蛙 A 一次能跳 m 米,青蛙 B 一次能跳 n 米,两只青蛙跳一次所花费的时间相同。纬度线总长 L 米。现在要你求出它们跳了几次以后才会碰面。
输入格式
输入只包括一行五个整数 x,y,m,n,L。
输出格式
输出碰面所需要的次数,如果永远不可能碰面则输出一行一个字符串 Impossible
。
输入输出样例
in:
1 2 3 4 5
out:
4
说明/提示
对于 100% 的数据,1≤x=y≤2×109,1≤m,n≤2×109,1≤L≤2.1×109。
这是一篇有详细证明的题解 qwq~
首先我们可以发现,
这个题就是为了让我们解一个方程:
x+km≡y+kn(modl)
其中 k 为所求。
让我们把这个看上去很 zz 的方程变化一下:
x+km−(y+kn)=lz,z∈Z
那么就是:
x−y+k(m−n)−lzk(m−n)−lz=0=−(x−y)
我们设 S=x−y,W=n−m
(注意这个地方有变号,即 m−n 被我设作 n−m,为的是让等式右边的 S 冠正号)。
这个式子便可写作:
kW+lz=S
诶,这不就是一个不定方程吗?
对啊,所以我们所要做的就是对这个不定方程求出最小解。
那么其实,
对于这个方程,
我们是要解出步数的最小值,
所以我们只需要求出k最小即可。
我们可以通过扩展欧几里德算法求出一组特解,
然后对于这组特解,我们再推导出最小解来。
但由于这个方程在解 exgcd 的时候,
那个方程转化成了:
kjW+lzj=(W,l)
那么我们求出的 kj 就是这个方程得一个特解。
之后,这个方程的所有解就可以表示成
ki=kj+tgcd(W,l)l
这是上面这个式子为什么可以这么做的证明:
若有 ax+by=c 且 a0x+b0y=c。
那么便有 a(x−x0)+b(y−y0)=0。
两边同时除以 gcd(a,b) 可得
gcd(a,b)a(x−x0)=−gcd(a,b)b(y−y0)(1)
而因为
(gcd(a,b)a,gcd(a,b)b)=1
所以由 (1) 可得 gcd(a,b)b 整除 (x−x0)。
所以很显然有
gcd(a,b)b×t=(x−x0),t∈Z
那么就有对于任意一个 xi,有
xi=x0+gcd(a,b)b×t
让我们回到原问题。因为
kj=kmin+gcd(W,l)l×t
这个方程对于 t∈Z 而言,想要通过一个特解推出最小解,可以如此做:
kmin=kjmodgcd(W,l)l
而因为这个 k 是建立在 exgcd 得出的方程上的,方程右边是 gcd(W,l) 而不是 S。所以最后我们需要将结果 ×gcd(W,l)S 。
.这个方程就是扩展欧几里得
代码这样
#include <bits/stdc++.h>
using namespace std;
long long k(long long a, long long b, long long &x, long long &y) {
//十年OI一场空,不开long long见祖宗
if (!b) {
x=1,y=0;
return a;
}
long long d=k(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main() {
long long x,y,m,n,l,s,t;
cin>>x>>y>>m>>n>>l;
long long d=k(m-n,l,s,t);
if((y-x)%d!=0){
cout<<"Impossible";
return 0;
}
cout<<((s*(y-x)/d)%abs(l/d)+abs(l/d))%abs(l/d);//处理负数
return 0;
}
各位大佬
关注+收藏+点赞
好吗