ZOJ ~ 3593 ~ One Person Game (擴充套件歐幾里得,不定方程)
阿新 • • 發佈:2018-12-12
題意
你要從A走到B,你每次可以走a步,b步,a+b步問最小需要走多少步?無法到達輸出 -1。
題解
先不考慮a+b步的情況,那麼我們要求解的就是:,如果,證明無解。
假設原方程一組解為x0,y0,那麼通解(x,y)為:,。
其實也就是兩條直線:,
取一條平行於y軸的直線 x = t :
如果 x 和 y 異號,假設x > 0,y < 0也就是往前走x次a步,往後走y次b步。x < 0, y > 0同理,這種情況答案為
如果 x 和 y 同號,其實也就是都往前(後)走x次a步,y次b步,考慮上可以走a+b的情況,答案也就是。
結合圖可知,越接近交點值越小,當 t 取 x 和 y 交點時,答案最小。
=》 ,但是 t 可能不是整數,所以我們要嘗試 t-1,t,t+1 三個值。
#include<bits/stdc++.h> using namespace std; typedef long long LL; void exgcd(LL a, LL b, LL& d, LL& x, LL& y) { if (!b) { d=a; x=1; y=0; } else { exgcd(b, a%b, d, y, x); y -= x*(a/b); } } LL cal(LL x, LL y) { if (x*y >= 0) return max(abs(x), abs(y)); else return abs(x)+abs(y); } LL solve(LL a, LL b, LL c) { LL GCD, x0, y0; exgcd(a, b, GCD, x0, y0); if (c%GCD) return -1; x0 *= c/GCD; y0 *= c/GCD; LL aa = a/GCD, bb = b/GCD; LL t = (y0-x0)/(aa+bb);//x0+a't=y0-b't,t = (y0-x0)/(a'+b') LL ans1 = cal(x0+bb*t, y0-aa*t); LL ans2 = cal(x0+bb*(t-1), y0-aa*(t-1)); LL ans3 = cal(x0+bb*(t+1), y0-aa*(t+1)); return min(min(ans1, ans2), ans3); } int main() { int T; scanf("%d", &T); while (T--) { LL A, B, a, b; scanf("%lld%lld%lld%lld", &A, &B, &a, &b); LL ans = solve(a, b, abs(A-B)); printf("%lld\n", ans); } return 0; } /* 2 0 1 1 2 0 1 2 4 */