uva11768 Lattice Point or Not

比较经典的扩展欧几里德求整数解的问题

对于两个点(x1,y1)(x2,y2),如果点为整数点,那么必定能通过扩展欧几里德求出区间中的整点个数,即对方程(y2-y1)x+(x1-x2)y=x1y2-x2y1 求解。

由于此题的点精确到小数后1位,我们可以将x1,y1,x2,y2分别放大10倍,问题转变成对方程[10*(y2-y1)]x+[10(x1-x2)]y=100*(x1y2-x2y1)求解。

记a=10*(y2-y1),b=10*(x1-x2) ,c=100*(x1y2-x2y1), g=gcd(a,b)

那么用扩展欧几里德可以得到aX+bY=gcd(a,b)的一组解。注意,这里得到的一组解仅保证abs(X+Y)取到最小值
判断需要求解的方程是否有解,只需要判断c%gcd(a,b)==0是否成立即可。

那么就可以得到需要求解的方程的一组解:X0=X*c/g, Y0=Y*c/g
此时就可以对区间有几个解进行计算了。
另外,因为之前扩展欧几里德写的少,所以xjb写了一发暴力,此处贴上代码。

正解

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int T;
LL x[2], y[2];
void read(LL &x)
{
    LL a, b;
    scanf("%lld.%lld", &a, &b);
    x = a * 10 + b;
}
void exgcd(LL a, LL b, LL& g, LL& x, LL& y)
{
    if (!b) g = a, x = 1, y = 0;
    else exgcd(b, a%b, g, y, x), y -= x * (a / b);
}
LL solve()
{
    LL ans = 0;
    for (int i = 0; i < 2; i++)read(x[i]), read(y[i]);
    if (x[0] > x[1] || x[0] == x[1] && y[0] > y[1]) {
        swap(x[0], x[1]);
        swap(y[0], y[1]);
    }

    if (x[0] == x[1]) {
        if (x[0] % 10)return 0;
        return max(0LL, y[1] / 10 - (y[0] + 9) / 10 + 1);
    }
    if (y[0] == y[1]) {
        if (y[0] % 10)return 0;
        return max(0LL, x[1] / 10 - (x[0] + 9) / 10 + 1);
    }

    LL a, b, g, X, Y;
    a = (y[1] - y[0]) * 10;
    b = (x[0] - x[1]) * 10;
    exgcd(a, b, g, X, Y);
    LL c = x[0] * y[1] - x[1] * y[0];
    if (c%g)return 0;
    X = X * c / g;
    x[0] = (x[0] + 9) / 10;
    x[1] = x[1] / 10;
    if (x[0] > x[1])return 0;
    LL st = abs(b / g);
    LL cx = X - (X - x[0]) / st * st;
    if (cx < x[0])cx += st;
    if (cx > x[1])return 0;
    return (x[1] - cx) / st + 1;
}
int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    scanf("%d", &T);
    while (T--) {
        printf("%lld\n", solve());
    }
}

暴力

#include<bits/stdc++.h>
using namespace std;
typedef long long LL ;
int T;
LL x[2], y[2];
LL gcd(LL a, LL b)
{
    return b == 0 ? a : gcd(b, a%b);
}
void read(LL &x)
{
    LL a, b;
    scanf("%lld.%lld", &a, &b);
    x = a * 10 + b;
}
int main()
{
    scanf("%d", &T);
    while (T--) {
        for (LL i = 0; i < 2; i++)read(x[i]), read(y[i]);
        /*for (int i = 0; i < 2; i++) {
            x[i] = (rand() % 200 + 1) * 10;
            y[i] = (rand() % 200 + 1) * 10;
        }*/
        //printf("%d %d %d %d\n", x[0], y[0], x[1], y[1]);
        if (x[0] > x[1] || x[0] == x[1] && y[1] > y[0]) {
            swap(x[0], x[1]);
            swap(y[0], y[1]);
        }
        if (x[0] == x[1] && (x[0] % 10) || y[0] == y[1] && (y[0] % 10)) {
            printf("0\n");
            continue;
        }
        if (x[0] == x[1] && y[0] == y[1]) {
            if (x[0] % 10 == 0 && y[0] % 10 == 0) {
                printf("1\n");
            }
            else printf("0\n");
            continue;
        }
        LL dx = abs(x[0] - x[1]);
        LL dy = abs(y[0] - y[1]);
        LL g = gcd(dx, dy);
        LL st = dx / g;
        LL cx = x[0], cy = y[0];
        LL ans = 0;
        for (LL i = 0; i <= 100 && cx <= x[1] && (cy - y[0])*(cy - y[1]) <= 0; i++) {
            if (cx % 10 == 0 && cy % 10 == 0) {
                long long gc = gcd(gcd(st, 10), gcd(dy / g, 10));
                LL t = 10 / gcd(gcd(st, 10), gcd(dy / g, 10));
                if (st)ans = 1 + (x[1] - cx) / (t*st);
                else ans = abs(y[1] - cy) / (dy / g * t) + 1;
                break;
            }
            cx += st;
            cy += (y[1] - y[0]) / g;
        }
        printf("%lld\n", ans);
    }
}

猜你喜欢

转载自blog.csdn.net/CharlieHuu/article/details/81672130
今日推荐