扩展欧几里求最优解
https://zoj.pintia.cn/problem-sets/91827364500/problems/91827369176
题意:有一数轴 , 问从A点到B点最少需要几步。可以有6中方式行走,左右a , b a+b.
解法:设走了x步a , y步b。有方程 ax + by = B-A ,转化为求|x| + |y|的最小值,x , y 分别是两条直线。
|x|+|y|最小值在x=x+bt与y=y-at两条直线交点附近。
#include <bits/stdc++.h> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define cin(a) scanf("%d",&a) #define pii pair<int,int> #define ll long long #define gcd __gcd #define mod 1000000007 #define INF 0x3f3f3f3f const ll inf = 0x3f3f3f3f; const int M = 1e9+7; const int N = 100009 ; ll x , y , d ; void gcd(ll a , ll b , ll &d , ll &x , ll &y) { if(b == 0) { x = 1 ; y = 0 ; d = a ; } else{ gcd(b , a%b , d , x , y); ll t = x ; x = y ; y = t - (a/b) * y ; } } ll cal(ll a , ll b , ll c) { gcd(a , b , d , x , y); if(c % d) return -1 ; else{ return 1; } } int main() { int t ; scanf("%d" , &t); while(t--) { ll A , B , a , b ; scanf("%lld%lld%lld%lld" , &A,&B , &a, &b); ll c = B - A ; ll t = cal(a , b , c); if(t == -1){ cout << -1 << endl ; continue ; } else { x *= c / d ; y *= c / d ; a /= d ; b /= d ; ll ans = inf * inf , tmp ;//inf要用ll,在这wa了几发 ll mid = (y - x) / (a + b);//mid为两直线交点 for(ll T = mid - 1 ; T <= mid + 1 ; T++) { if((x + b*T)*(y - a*T) >= 0)//x ,y 同号 { tmp = max(abs(x+b*T) , abs(y-a*T));//取最大那个就可以,相同部分取x+y每步 } else{ tmp = abs(x - y + (a + b) * T);//都取 } ans = min(tmp , ans); } cout << ans << endl ; } } return 0; }