UVA - 11768 Lattice Point or Not (拓展gcd)

Now a days a very common problem is:“The coordinate of two points in Cartesian coordinate system is (200, 300) and(4000, 5000). If these two points are connected we get a line segment. How manylattice points are there on this line segment.” You will have to
do a similartask in this problem – the only difference is that the terminal coordinates canbe fractions.

Input

First line of the input file contains a positive integer N(N<=50000) that denotes how many lines of inputs follow. This line isfollowed by N lines each of which contains four floating-point numbers x1, y1,x2, y2 (0< |x1|, |y1|, |x2|,
|y2|<=200000). These floating-point numbers has exactly one digit after thedecimal point.

Output

For each line of input exceptthe first line produce one line of output. This line contains an integer whichdenotes how many lattice points are there on the line segment that connects thetwo points (x1, y1) and (x2, y2).

SampleInput                              Output for Sample Input


3

10.1 10.1 11.2 11.2

10.2 100.3 300.3 11.1

1.0 1.0 2.0 2.0


1

0

2


Problemsetter: Shahriar Manzoor

Special Thanks: Derek Kisman

题意:求一条线段经过的整数点个数

思路:先将线段转换成直线方程,那么我们就可以用拓展gcd来求解了,然后就是找这两个点范围内的解就是了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
typedef long long ll;
using namespace std;

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

ll sovle(double X1, double Y1, double X2, double Y2) {
	ll x1 = X1*10, x2 = X2*10, y1 = Y1*10, y2 = Y2*10;
	if (x1 == x2) {
		if (x1 % 10)
			return 0;
		y1 = ceil(min(Y1, Y2));
		y2 = floor(max(Y1, Y2));
		return max(y2-y1+1, 0ll);
	}
	if (y1 == y2) {
		if (y1 % 10)
			return 0;
		if (X2 < X1)
			swap(X2, X1);
		x1 = ceil(X1), x2 = floor(X2);
		return max(x2-x1+1, 0ll);
	}
	ll a = (y2-y1)*10, b = (x1-x2)*10, c = x1*y2-x2*y1;
	ll x, y, d, k1 = 0;
	if (X2 < X1)
		swap(X2, X1);
	x1 = ceil(X1), x2 = floor(X2);
	if (x1 > x2)
		return 0;
	gcd(a, b, d, x, y);
	if (c % d != 0)
		return 0;
	a /= d, b /= d;
	x *= (c/d), y *= (c/d);
	if (b < 0)
		b = -b;
	x = x-(x-x1)/b*b;
	x -= b;
	while (x < x1)
		x += b;
	k1 = 0;
	while (x + k1 * b <= x2)
		k1++;
	return k1;
}

int main() {
	double x1, y1, x2, y2;
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
		ll ans = sovle(x1, y1, x2, y2);
		printf("%lld\n", ans);
	}
	return 0;
}
时间: 2024-12-16 04:31:52

UVA - 11768 Lattice Point or Not (拓展gcd)的相关文章

UVA 11768 - Lattice Point or Not(数论)

UVA 11768 - Lattice Point or Not option=com_onlinejudge&Itemid=8&page=show_problem&category=516&problem=2868&mosmsg=Submission+received+with+ID+13823461" target="_blank" style="">题目链接 题意:给定两个点,构成一条线段.这些点都是十分

UVA 11768 Lattice Point or Not

扩展欧几里得,给两个点,就可以求出直线方程为 (yy-y)*x0 + (x-xx)*y0 = x*yy - y*xx,求的是在线段上的整点个数.所以就是(yy-y)*10*x0 + (x-xx)*10*y0 = x*yy - y*xx满足条件的解的个数.用exgcd搞之后求出一个解,再求出在线段上第一个整点的位置,然后再求有多少个在线段上的点. exgcd有点忘了,还有就是特殊情况的判断(比如平行坐标轴),另外就是不能交换输入点,输入 1.0 0.3 0.3 10.0交换后就是0.3 0.3 1

UVA - 11768 Lattice Point or Not (扩展欧几里得)

求一条线段上有多少个整点. 是道扩欧基础题,列出两点式方程,然后分四种情况讨论即可.但细节处理较多很容易写挫(某zzWA了十几发才过掉的). 由于数据精度较小,浮点数比较没有用eps,直接==比较了. 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 6 void exgcd(ll a,ll b,ll& x,ll& y,ll& g) { 7 if(!b)x=1,y=0

uva 10548 - Find the Right Changes(拓展欧几里得)

题目链接:uva 10548 - Find the Right Changes 题目大意:给定A,B,C,求x,y,使得xA+yB=C,求有多少种解. 解题思路:拓展欧几里得,保证x,y均大于等于0,确定通解中t的取值. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef long long ll; co

拓展gcd解不定线性方程ax+by=c模版

拓展gcd解不定线性方程ax+by=c模版 /** 解不定方程 ax+by=c */ ll a,b,c; ll x,y; ll exgcd(ll a,ll b,ll &x,ll &y) { if(b==0){ x=1;y=0; return a; } ll r=exgcd(b,a%b,x,y); ll t=y; y=x-a/b*y; x=t; return r; } bool NLE(ll a,ll b,ll c,ll &x,ll &y) /**解不定方程 ax+by=c;

uva 1549 - Lattice Point(暴力)

题目链接:uva 1549 - Lattice Point 题目大意:给定圆半径,以原点为圆心,求园内有多少个整数点. 解题思路:首先坐标轴将圆分成4份,所以只要单独考虑每一块的个数乘4再加1即可(原点) #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double pi = 4 * atan(1.0);

UVa 11768 格点判定(扩展欧几里得求线段整点)

https://vjudge.net/problem/UVA-11768 题意: 给定两个点A(x1,y1)和B(x2,y2),均为0.1的整数倍.统计选段AB穿过多少个整点. 思路: 做了这道题之后对于扩展欧几里得有了全面的了解. 根据两点式公式求出直线 ,那么ax+by=c 中的a.b.c都可以确定下来了. 接下来首先去计算出一组解(x0,y0),因为根据这一组解,你可以写出它的任意解,其中,K取任何整数. 需要注意的是,这个 a' 和 b' 是很重要的,比如说 b' ,它代表的是x每隔 b

UVA - 1602 Lattice Animals (暴力+同构判定)

题目链接 题意:求能放进w*h的网格中的不同的n连通块个数(通过平移/旋转/翻转后相同的算同一种),1<=n<=10,1<=w,h<=n. 刘汝佳的题真是一道比一道让人自闭...QAQ~~ 这道题没什么好的办法,Polya定理也毫无用武之地,只能暴力构造出所有可能的连通块,然后用set判重,比较考验基本功. 连通块可以用一个结构体D来表示,D的n代表黑块数量,然后有至多10个点P(x,y),用另一个结构体数组P[N]来表示. 问题的关键在于如何判重. 首先要知道set是通过<

UVA 1602 Lattice Animals解题思路(打表+set)

题目链接 https://vjudge.net/problem/UVA-1602 紫书的一道例题,跟之前的很多题目有很多不同. 本题不像是一般的dfs或bfs这样的搜索套路,而是另一种枚举思路. 题意: 输入n. w. h(1≤n≤10,1≤w,h≤n),求能放在w*h网格里的不同的n连块的个数(平移. 旋转. 翻转后相同的图形算作同一种). 思路: 思路很明确,生成图形后判重,加入重复表或弃掉. 本题的重点就在生成和判重. 我的思路: 连通块的生成:通过维护一个int open[10][10]