ZOJ 3593 One Person Game(ExGcd + 最优解)题解

思路:题意转化为求 (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

ZOJ 3593 One Person Game(ExGcd + 最优解)题解的相关文章

ZOJ 3593 One Person Game

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

ZOJ Monthly, June 2014 月赛BCDEFGH题题解

比赛链接:点击打开链接 上来先搞了f.c,,然后发现状态不正确,一下午都是脑洞大开,, 无脑wa,无脑ce...一样的错犯2次.. 硬着头皮搞了几发,最后20分钟码了一下G,不知道为什么把1直接当成不能加油的站就会wa..太弱.. 唔···太懒第二天才发题解.. B:Gears 并查集 题解:点击打开链接 C:Consecutive Blocks 离散化一下然后模拟 题解:点击打开链接 D:An Easy Game 设dp[i][j]为前i个位置已经匹配了j个位置的方法数. #include <

zoj 3836 Circulation pipe , exgcd

Circulation pipe Time Limit: 4 Seconds      Memory Limit: 65536 KB Darkgy is a transport pipe master. One day, due to some strange redstone signal, an Iron pipe changed its direction and make a part of the pipe system become a circulation pipe. The c

One Person Game(zoj3593+扩展欧几里德)

One Person Game Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Practice ZOJ 3593 Appoint description:  System Crawler  (2015-04-29) Description There is an interesting and simple one person game. Suppose ther

[数论]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,L

[数论]拓展欧几里得算法

欧几里得算法(辗转相除法) 用来求解最大公约数 1 int gcd(int a,int b){ 2 return b ? gcd(b,a%b) : a; 3 } 在 #include<algorithm> 中也可以直接调用 __gcd(a,b) 拓展欧几里得算法 求解不定方程: 引理:存在 x , y 使得 ax+by=gcd(a,b) 设a,b,c为任意整数,若方程ax+by=c的一组解是(x0,y0),则它的任意整数解都可以写成(x0+k*b/gcd(a,b),y0-k*a/gcd(a,b

C++之路进阶——最大流(善意的投票)

F.A.Qs Home Discuss ProblemSet Status Ranklist Contest ModifyUser  hyxzc Logout 捐赠本站 Notice:由于本OJ建立在Linux平台下,而许多题的数据在Windows下制作,请注意输入.输出语句及数据类型及范围,避免无谓的RE出现. 1934: [Shoi2007]Vote 善意的投票 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 1646  Solved: 1006[

扩展欧几里德算法详解

扩展欧几里德算法 谁是欧几里德?自己百度去 先介绍什么叫做欧几里德算法 有两个数 a b,现在,我们要求 a b 的最大公约数,怎么求?枚举他们的因子?不现实,当 a b 很大的时候,枚举显得那么的na?ve ,那怎么做? 欧几里德有个十分又用的定理: gcd(a, b) = gcd(b , a%b) ,这样,我们就可以在几乎是 log 的时间复杂度里求解出来 a 和 b 的最大公约数了,这就是欧几里德算法,用 C++ 语言描述如下: 由于是用递归写的,所以看起来很简洁,也很好记忆.那么什么是扩

ZOJ Monthly,Feburary 2012 部分题解

题目链接:点击打开链接 ZOJ 3573 Under Attack 距离做这套题到写题解间隔比较久,题意有些忘了.. #include <iostream> #include <cstdio> #include <algorithm> #include <string> #include <cmath> #include <cstring> #include <queue> #include <set> #in