表白的数论

题意 : 从s走到t, 距离为c,现在每步只能走a,b,a+b三种长度的步数。 a,b,c均为整数,现在问至少走多少步能到达终点。

 

思路: 开始的时候一样就看出了用扩展欧几里德做,算出来ax+by=c的整数解,然后再波动,算的过程中注意a+b的情况并上。 后来一直wa。

后来又换了一种做法,即看成这个人可以走三种情况a,b或a,a+b,或b,a+b。

这三种情况算出后再进行波动。 第二种想法是严密的,没有漏洞出现。

AC代码:

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
typedef long long LL;
const LL INF = 1LL<<62;
LL s, t, a, b;

LL gcd(LL &x,LL &y,LL  a,LL  b)
{
    if(b==0)
    {
        x = 1;
        y = 0;
        return a;
    }
    LL   d = gcd(x,y,b,a%b);
    LL  t = x;
    x = y;
    y = t - a/b*y;
    return d;
}

LL abs(LL a)
{
    return a > 0 ? a:-a;
}

void init()
{
    scanf("%lld%lld%lld%lld", &s, &t, &a, &b);
}

LL  get(LL a, LL b)
{
    LL c, x, y, g, ans, xx, yy;

    c = s - t;
    if(c < 0) c = -c;
    g = gcd(x, y, a, b);

    if(c % g)
    {
        return INF;
    }

    a /= g;
    b /= g;
    c /= g;
    x = x*c;
    y = y*c;
    x = (x%b + b)%b;
    y = (y%a + a)%a;
    ans = INF;
    for(int i=-5; i<=5; i++)
    {
        xx = x+b*i;
        yy = (c - xx*a)/b;
        ans = min(ans,abs(xx) + abs(yy));
    }
    for(int i=-5; i<=5; i++)
    {
        yy = y+a*i;
        xx = (c - yy*b)/a;
        ans = min(ans, abs(xx) + abs(yy));
    }
    return ans;
}

int main()
{
    int t;
    LL ans;
    scanf("%d", &t);
    while(t--)
    {
        init();
        ans = get(a,b);
        ans = min(ans, get(a+b,a) );
        ans = min(ans, get(a+b,b) );
        if(ans == INF)
            printf("-1\n");
        else printf("%lld\n", ans);
    }
    return 0;
}

 

 

posted @ 2012-09-26 13:50  Gu Feiyang  阅读(202)  评论(0)    收藏  举报