【扩展欧几里得】BZOJ1477-青蛙的约会
一直在WA,后来我发现我把东西看反了……
【题目大意】
给出一个长度为L的环状坐标轴,两个点开始时位于(X,0)、(Y,0)。每次两点分别往右边移动m和n,问能否相遇?
【思路】
由题意,可得:
X+mt=Y+nt(mod L)
(X+mt)-(Y+nt)=L*k
(n-m)t+L*k=X-Y。
可以用扩展欧几里得来做。具体来说,显然要满足n-m和L的最大公约数(记为d)要整除X-Y,否则无解。这个可以在扩展欧几里得中求出。
式子可以化简为:[(n-m)/d]*t+(L/d)*k=(X-Y)/d。因此通解为 t'=t0+(L/d)*n(n∈Z)
由于扩展欧几里得杰出的结果其实是(n-m)*t+L*k=d的解,因此要乘以(X-Y)/d才是答案。然后往上加得到第一个大于0的解即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 8 ll extgcd(ll a,ll b,ll &x,ll &y) 9 { 10 ll ret; 11 if (b==0) 12 { 13 x=1,y=0; 14 return a; 15 } 16 ret=extgcd(b,a%b,x,y); 17 ll tmp=x; 18 x=y; 19 y=tmp-(a/b)*y; 20 return ret; 21 } 22 23 int main() 24 { 25 ll X,Y,m,n,L,x,y; 26 scanf("%lld%lld%lld%lld%lld",&X,&Y,&m,&n,&L); 27 ll d=extgcd(n-m,L,x,y); 28 if ((X-Y)%d!=0) puts("Impossible");else 29 { 30 ll delta=abs(L/d); 31 x=(x*(X-Y)/d+delta)%delta; 32 while (x<0) x=(x+delta)%delta; 33 printf("%lld",x); 34 35 } 36 return 0; 37 }