ZOJ 3593.One Person Game-扩展欧几里得(exgcd)

智障了,智障了,水一水博客。

本来是个水题,但是for循环遍历那里写挫了。。。

 

One Person Game

Time Limit: 2 Seconds      Memory Limit: 65536 KB

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 ABa and b, separated by spaces. (-231 ≤ AB < 231, 0 < ab < 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 }

 

 

水一水,溜了,慢慢补。去看主席树了。。。

posted @ 2018-04-27 18:36  ZERO-  阅读(288)  评论(0编辑  收藏  举报