天天看点

SGU106 The equation

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="font-size:14px;">题意:给出直线ax+by+c=0的参数a, b, c,求直线在 x ∈[x1, x2],y ∈[y1, y2] 上有多少整点。</span></span>
           

题解:首先特判a或b等于零的情况。若a,b非零,欧几里得搞出一组解,然后算出delta_x, delta_y(通解式子),按直线的斜率>0或<0分类。然后求出x的最小合法取值(即对应的y也合法),然后在x的可滑动区间和y的可滑动区间之间求一个最小值就好了。

写这题的时候开始代码还能看,后来一次又一次地被细节坑,然后为了AC代码就越来越乱了。。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
#define f1(y) ((c-b*(y)) / a) //已知y对应的x
#define f2(x) ((c-a*(x)) / b) //已知x对应的y
LL a, b, c;
LL x1, x2;
LL y1, y2;

LL Min(LL a, LL b) { return a<b ? a : b; }
LL Max(LL a, LL b) { return a>b ? a : b; }
LL Abs(LL x) { return x>0?x:-x; }

void exgcd(LL a, LL b, LL&d, LL&x, LL&y) {
	if (!b) { d = a; x = 1; y = 0; }
	else { exgcd(b, a%b, d, y, x); y -= x*(a/b); }
}

LL solve()
{
	LL g, x, y, minx, ry;
	exgcd(a, b, g, x, y);
	if (c % g != 0) return 0;
	x *= c / g;
	y *= c / g;
	LL dtx = b/g, dty = a/g;
	if (dtx < 0) dtx *= -1, dty *= -1;
	LL k1 = (x1 - x) / dtx, k2;
	x += k1 * dtx;
	x += (x1-x)/dtx*dtx;
	while (x < x1) x += dtx; //以上三行代码很冗余。为了AC,只有无节操乱搞了。
	if (dty<0) { //斜率>0
		dty *= -1;
		k2 = (y1 - y) / dty; //y的最小取值
		minx = Max(x, f1(y+k2*dty));//x的最小取值,要么是x最小,要么是y最小对应的x
		ry = f2(minx);
		if (ry > y2 || minx > x2) return 0;
		else return Min((x2-minx)/dtx+1, (y2-ry)/dty+1);
	}
	else { //斜率<0
		k2 = (y1 - y) / dty;
		y += k2 * dty;
		y += (y2 - y) / dty * dty;
		while (y+dty<=y2) y += dty;//搞出y的最大取值
		minx = Max(x, f1(y)); //x的最小取值,要么是x最小,要么是y最大对应的x
		ry = f2(minx);
		if (ry < y1 || minx > x2) return 0;
		else return Min((x2-minx)/dtx+1, (ry-y1)/dty+1);
	}
}

LL special()
{
	if (a==0 && b==0)
		return (c==0) * (x2-x1+1) * (y2-y1+1);
	if (a==0) {
		if (c % b != 0 || c/b<y1 || c/b>y2) return 0;
		return x2 - x1 + 1;
	}
	else {
		if (c % a != 0 || c/a<x1 || c/a>y2) return 0;
		return y2 - y1 + 1;
	}
}

int main()
{
	cin >> a >> b >> c;
	c = -c;
	cin >> x1 >> x2;
	cin >> y1 >> y2;
	if (x1>x2 || y1>y2) cout<<"0\n";
	else if (a==0 || b==0) cout << special() << '\n';
	else cout << solve() << '\n';
	return 0;
}