思路:题意转化为求 (ax+by=dis) || (ax+cy=dis) || (bx+cy=dis) 三个式子有解时的最小|x| + |y|。显然求解特解x,y直接用扩展欧几里得,那么怎么求|x| + |y|?xy关系为一条直线,那么|x| + |y|应该是在x取0或者y取0的时候,但是要整数,所以只能在周围取几个点。我们知道x=x1+b/gcd*t,那么x1+b/gcd*t = 0可以解得 t = -x1 * gcd / b。然后在附近取几个点。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define LS(n) node[(n)].ch[0] #define RS(n) node[(n)].ch[1] using namespace std; typedef long long ll; const int INF = 0x3f3f3f3f; const int maxn = 32767 + 10; ll ex_gcd(ll a, ll b, ll &x, ll &y){ ll d, t; if(b == 0){ x = 1; y = 0; return a; } d = ex_gcd(b, a%b, x, y); t = x-a/b*y; x = y; y = t; return d; } ll dis; //求|x|+|y|最小 ll solve(ll a, ll b){ ll x, y, d = ex_gcd(a, b, x, y); if(dis % d != 0) return INF; x = x * dis / d; y = y * dis / d; a /= d, b /= d; ll ans = abs(x) + abs(y); ll k; k = -x / b - 5; for(int i = 0; i <= 10; i++){ ans = min(ans, abs(x + b * (k + i)) + abs(y - a * (k + i))); } k = y / a - 5; for(int i = 0; i <= 10; i++){ ans = min(ans, abs(x + b * (k + i)) + abs(y - a * (k + i))); } return ans; } int main(){ int T; scanf("%d", &T); while(T--){ ll a, b, A, B; scanf("%lld%lld%lld%lld", &A, &B, &a, &b); dis = abs(A - B); ll ans; ans = min(solve(a, a + b), min(solve(a, b), solve(b, a + b))); printf("%lld\n", ans == INF? -1 : ans); } return 0; }
原文地址:https://www.cnblogs.com/KirinSB/p/9846574.html
时间: 2024-10-31 13:48:17