码迷,mamicode.com
首页 > 其他好文 > 详细

luogu2833 等式

时间:2018-05-07 00:46:11      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:return   +=   代码   ace   扩展欧几里得   AC   多少   cpp   efi   

题目大意

给出\(a,b,c,x_1,x_2,y_1,y_2\),求满足\(ax+by+c=0\),且\(x\in[x1,x2],y\in [y1,y2]\)的整数解有多少对。

题解

用扩展欧几里得算法算出方程\(ax+by=-c\)的一个解,再将该解移动到题目所要求的范围内。具体操作看代码。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define ll long long
#define NoAns {printf("0\n");return 0;}

ll Exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll d = Exgcd(b, a % b, x, y);
    ll tx = x;
    x = y;
    y = tx - y * (a / b);
    return d;
}

ll Gcd(ll a, ll b)
{
    return b ? Gcd(b, a%b) : a;
}

bool Solve(ll a, ll b, ll c, ll &x, ll &y, ll &deltaX, ll &deltaY)
{
    int gcd = Gcd(a, b);
    if (c%gcd != 0)
        return false;
    Exgcd(a, b, x, y);//易忘点:好好下定义,传入的参数不是a%gcd,b%gcd
    x *= c / gcd;
    y *= c / gcd;
    deltaX = b / gcd;
    deltaY = -a / gcd;//易忘点:负号
    return true;
}

ll MoveToRange(ll orgP, ll delta, ll l, ll r, ll toP, bool &moveFailed)
{
    ll k = (toP - orgP) / delta;
    int higherP = delta > 0 ? 1 : -1;
    if (orgP + k * delta > r)
        k-=higherP;//注意此处不能直接--,因为delta<0时k越小k*delta越大
    else if (orgP + k * delta < l)
        k+=higherP;
    if (orgP + k * delta > r || orgP + k * delta < l)
        moveFailed = true;
    return k;
}

int main()
{
    ll a, b, c, x1, x2, y1, y2;
    scanf("%lld%lld%lld%lld%lld%lld%lld", &a, &b, &c, &x1, &x2, &y1, &y2);

    if (x2 < x1 || y2 < y1)
        NoAns

    if (a == 0 && b == 0)
    {
        if (c == 0)
            printf("%lld\n", (x2 - x1 + 1) * (y2 - y1 + 1));
        else
            NoAns
        return 0;
    }

    if (a == 0)
    {
        if (c%b == 0 && y1 <= -c / b && -c / b <= y2)
            printf("%lld\n", x2 - x1 + 1);
        else
            NoAns
        return 0;
    }

    if (b == 0)
    {
        if (c%a == 0 && x1 <= -c / a && -c / a <= x2)
            printf("%lld\n", y2 - y1 + 1);
        else
            NoAns
        return 0;
    }

    ll x, y, deltaX, deltaY;
    if (!Solve(a, b, -c, x, y, deltaX, deltaY))
        NoAns

    bool moveFailed = false;
    ll kx1 = MoveToRange(x, deltaX, x1, x2, x1, moveFailed);
    ll kx2 = MoveToRange(x, deltaX, x1, x2, x2, moveFailed);
    ll ky1 = MoveToRange(y, deltaY, y1, y2, y1, moveFailed);
    ll ky2 = MoveToRange(y, deltaY, y1, y2, y2, moveFailed);
    if (moveFailed)
        NoAns

    if (kx1 > kx2)
        swap(kx1, kx2);
    if (ky1 > ky2)
        swap(ky1, ky2);
    ll kLow = max(kx1, ky1), kHigh = min(kx2, ky2);
    if (kLow > kHigh)
        NoAns

    printf("%lld\n", kHigh - kLow + 1);
    return 0;
}

luogu2833 等式

标签:return   +=   代码   ace   扩展欧几里得   AC   多少   cpp   efi   

原文地址:https://www.cnblogs.com/headboy2002/p/9000407.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!