UVA 11768 - Lattice Point or Not(数论)

UVA 11768 - Lattice Point or Not

题目链接

题意:给定两个点,构成一条线段,这些点都是十分位形式的,求落在这个直线上的正数点。

思路:先把直线表达成a x + b y = c的形式,a,b, c都化为整数表示,然后利用扩展gcd求出x和y的通解,然后已知min(x1, x2) <= x <= max(x1, x2), min(y1, y2) <= y <= max(y1, y2),这样一来就可以求出通解中t的范围,t能取的整数就是整数解,就得到答案。

值得注意的是,直线为平行坐标系的情况,要特殊判断一下

代码:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;

const long long INF = 0x3f3f3f3f3f3f3f;
int t;
long long xx1, yy1, xx2, yy2;
long long a, b, c;

long long read(){
	double t;
	scanf("%lf", &t);
	return (long long)(10 * (t + 0.05));
}

long long gcd(long long a, long long b) {
	if (!b) return a;
	return gcd(b, a % b);
}

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

void build() {
	a = (yy2 - yy1) * 10;
	b = (xx1 - xx2) * 10;
	c = (yy2 - yy1) * xx1 + (xx1 - xx2) * yy1;
	long long t = gcd(gcd(a, b), c);
	a /= t; b /= t; c /= t;
}

long long solve() {
	long long ans = 0;
	long long x, y;
	long long d = exgcd(a, b, x, y);
	long long up = INF, down = -INF;
	if (xx1 > xx2) swap(xx1, xx2);
	if (yy1 > yy2) swap(yy1, yy2);
	if (c % d) return ans;
	if (b / d > 0) {
		down = max(down, (long long)ceil((xx1 * d * 1.0 / 10 - x * c * 1.0) / b));
		up = min(up, (long long)floor((xx2 * d * 1.0 / 10 - x * c * 1.0) / b));
 	}
 	else if (b / d < 0) {
 		up = min(up, (long long)floor((xx1 * d * 1.0 / 10 - x * c * 1.0) / b));
		down = max(down, (long long)ceil((xx2 * d * 1.0 / 10 - x * c * 1.0) / b));
  	}
  	else if (xx1 % 10) return ans;
  	if (a / d > 0) {
  		down = max(down, (long long)ceil((y * c * 1.0 - d * yy2 * 1.0 / 10) / a));
  		up = min(up, (long long)floor((y * c * 1.0 - d * yy1 * 1.0 / 10) / a));
   	}
   	else if (a / d < 0) {
   		up = min(up, (long long)floor((y * c * 1.0 - d * yy2 * 1.0 / 10) / a));
  		down = max(down, (long long)ceil((y * c * 1.0 - d * yy1 * 1.0 / 10) / a));
   	}
   	else if (yy1 % 10) return ans;
   	if (down <= up)
   		ans += up - down + 1;
	return ans;
}

int main() {
	scanf("%d", &t);
	while (t--) {
		xx1 = read(); yy1 = read(); xx2 = read(); yy2 = read();
		build();
		printf("%lld\n", solve());
 	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值