luogu2833 等式

题目大意

给出(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;
}
原文地址:https://www.cnblogs.com/headboy2002/p/9000407.html