ZOJ 3593.One Person Game-扩展欧几里得(exgcd)
智障了,智障了,水一水博客。
本来是个水题,但是for循环遍历那里写挫了。。。
There is an interesting and simple one person game. Suppose there is a number axis under your feet. You are at point A at first and your aim is point B. There are 6 kinds of operations you can perform in one step. That is to go left or right by a,b and c, here c always equals to a+b.
You must arrive B as soon as possible. Please calculate the minimum number of steps.
Input
There are multiple test cases. The first line of input is an integer T(0 < T ≤ 1000) indicates the number of test cases. Then T test cases follow. Each test case is represented by a line containing four integers 4 integers A, B, a and b, separated by spaces. (-231 ≤ A, B < 231, 0 < a, b < 231)
Output
For each test case, output the minimum number of steps. If it's impossible to reach point B, output "-1" instead.
Sample Input
2 0 1 1 2 0 1 2 4
Sample Output
1 -1
一开始没看懂题,后来懂了,c=a+b,所以就有3个方程,分别是a*x+b*y=r,a*x+c*y=r,b*x+c*y=r;
扩展欧几里得求出来gcd之后,通过判断r是不是gcd的倍数得到方程有没有解,然后 go on。。。
因为扩展欧几里得求出来的x和y并不是最优解,所以通过x和y的通式,x=x0+b/gcd*k;y=y0-a/gcd*k;(k为倍数)
本来自己想的是最优解和求出来的一般解应该差不了多少,就直接从-100到100遍历的,结果发现一直wa,学长说要找方程所在直线与源点距离最近的才是结果。
就是确定一下for的范围,不是瞎想的-100到100就以为能水过去。。。
首先x=x0+b/gcd*k,求出来k的范围,就是[-x0*gcd/b-1,-x0*gcd/b+1],在这个范围内for一遍,然后再通过y的通解,求出来的k的范围再for一遍就得到最优解了。
我智障,算y的k的时候,应该/a,我写成/b了_(:з」∠)_
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<stack> 10 using namespace std; 11 typedef long long ll; 12 const int maxn=1e5+10; 13 const int inf=0x3f3f3f3f; 14 const int eps=1e-6; 15 16 ll exgcd(ll a,ll b,ll &x,ll &y){ 17 if(b==0){ 18 x=1;y=0; 19 return a; 20 } 21 ll r=exgcd(b,a%b,x,y); 22 ll t=y; 23 y=x-(a/b)*y; 24 x=t; 25 return r; 26 } 27 28 ll fun(ll a,ll b,ll r){ 29 ll x,y; 30 ll gcd=exgcd(a,b,x,y); 31 if(r%gcd!=0)return -1; 32 else{ 33 x*=r/gcd; 34 y*=r/gcd; 35 ll k1=-1.0*x*gcd/b-1,k2=-1.0*x*gcd/b+1; 36 ll kk1=1.0*y*gcd/a-1,kk2=1.0*y*gcd/a+1;//y是除以a,智障了,写成除以b了。 37 ll ans=fabs(x)+fabs(y); 38 for(ll i=k1;i<=k2;i++){ 39 if(fabs(x+i*b/gcd)+fabs(y-i*a/gcd)<ans) 40 ans=fabs(x+i*b/gcd)+fabs(y-i*a/gcd); 41 42 } 43 for(ll i=kk1;i<=kk2;i++){ 44 if(fabs(x+i*b/gcd)+fabs(y-i*a/gcd)<ans) 45 ans=fabs(x+i*b/gcd)+fabs(y-i*a/gcd); 46 47 } 48 return ans; 49 50 } 51 } 52 53 int main(){ 54 int t; 55 cin>>t; 56 while(t--){ 57 ll A,B,a,b,c; 58 cin>>A>>B>>a>>b; 59 c=a+b; 60 ll r=fabs(A-B); 61 ll h1=fun(a,b,r); 62 ll h2=fun(a,c,r); 63 ll h3=fun(b,c,r); 64 if(h1==-1&&h2==-1&&h3==-1)cout<<"-1"<<endl; 65 else{ 66 ll ans=min(h1,h2); 67 ans=min(ans,h3); 68 cout<<ans<<endl; 69 } 70 } 71 }
水一水,溜了,慢慢补。去看主席树了。。。