[数论]ZOJ3593 One Person Game

题意:一个人要从A走到B  只能走a布、b步、(a+b)步,可以往左或右走

     问 最少要走几步,不能走到的输出-1

可以列出方程 $ax+by=A-B$

或者     $ax+(a+b)y=A-B$

或者     $bx+(a+b)y=A-B$

要取这三个方程的最小的$(x+y)$

根据$ax+by=gcd(a, b) $

当$A-B$不是$gcd$的倍数时 就不能走到

利用ex_gcd可以分别求出这三个方程的解,但求出的这组并非最小的

因此利用枚举斜率 得到的交点为最小的一组解

 1 LL exgcd(LL a,LL b,LL &x,LL &y)
 2 {
 3     LL d=a;
 4     if(b!=0)
 5     {
 6         d=exgcd(b,a%b,y,x);
 7         y-=(a/b)*x;
 8     }
 9     else  x=1,y=0;
10     return d;
11 }
12 LL Abs(LL x)
13 {
14     return x<0? -x:x;
15 }
16 LL A;
17 LL gao(LL a, LL b)
18 {
19     LL x, y;
20     LL g=exgcd(a, b, x, y);
21     x=x*(A/g), y=y*(A/g);
22     a/=g, b/=g;
23 
24     LL ans=Abs(x)+Abs(y);
25     for(int i=-10;i<10;i++)
26         ans=min(ans, Abs(x+(-x/b+i)*b)+Abs(y-(-x/b+i)*a));
27     for(int i=-10;i<10;i++)
28         ans=min(ans, Abs(x+(y/a+i)*b)+Abs(y-(y/a+i)*a));
29     return ans;
30 }
31 int main()
32 {
33     int t;
34     LL B,a,b;
35     cin>>t;
36     while(t--)
37     {
38         cin>>A>>B>>a>>b;
39         A=Abs(A-B);
40         if(!A)
41         {
42             puts("0");
43             continue;
44         }
45         if(A%__gcd(a, b))
46         {
47             puts("-1");
48             continue;
49         }
50         cout<<min(gao(a, b), min(gao(a+b, a), gao(a+b, b)))<<endl;
51     }
52     return 0;
53 }
ZOJ 3593
原文地址:https://www.cnblogs.com/Empress/p/4382122.html