题目大意
给出(a,b,c,x_1,x_2,y_1,y_2),求满足(ax+by+c=0),且(xin[x1,x2],yin [y1,y2])的整数解有多少对。
题解
用扩展欧几里得算法算出方程(ax+by=-c)的一个解,再将该解移动到题目所要求的范围内。具体操作看代码。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define NoAns {printf("0
");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
", (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
", x2 - x1 + 1);
else
NoAns
return 0;
}
if (b == 0)
{
if (c%a == 0 && x1 <= -c / a && -c / a <= x2)
printf("%lld
", 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
", kHigh - kLow + 1);
return 0;
}