UVA11768 - Lattice Point or Not

链接

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2868

题解

这题本身不难,但是边界情况容易造成 W A \color{red}WA
我先把坐标读入进来并且乘以 10 10 ,容易写出直线的一般方程 ( y 1 y 2 ) x + ( x 2 x 1 ) y = x 2 y 1 x 1 y 2 (y_1-y_2)x+(x_2-x_1)y=x_2y_1-x_1y_2
用字母代替系数,得到直线方程 a x + b y = c ax+by=c
现在就是要找横纵坐标都是 10 10 的倍数的点,其个数就是答案
解不定方程 10 a x + 10 b y = c 10ax+10by=c x [ x 1 , x 2 ] x\in[x_1,x_2] ,解的个数就是答案
如果 ( 10 ( a , b ) ) ̸ c (10(a,b))\not|c ,方程无解,点数是 0 0
否则解 10 a x + 10 b y = ( 10 a , 10 b ) 10ax'+10by'=(10a,10b)
假设解出一组 x = x 0 , y = y 0 x'=x_0,y'=y_0
解集构造为 x = x 0 c ( 10 a , 10 b ) + k b ( a , b ) x=x_0\frac{c}{(10a,10b)}+k\frac{b}{(a,b)}
10 x [ x 1 , x 2 ] 10x\in[x_1,x_2]
0.1 x 1 x 0 c ( 10 a , 10 b ) + k b ( a , b ) 0.1 x 2 0.1x_1\leq x_0\frac{c}{(10a,10b)}+k\frac{b}{(a,b)} \leq 0.1x_2
解得 ( a , b ) b ( 0.1 x 1 x 0 c ( 10 a , 10 b ) ) k ( a , b ) b ( 0.1 x 2 x 0 c ( 10 a , 10 b ) ) \frac{(a,b)}{b}(0.1x_1-x_0\frac{c}{(10a,10b)})\leq k \leq\frac{(a,b)}{b}(0.1x_2-x_0\frac{c}{(10a,10b)})
利用取整函数求出 k k 的个数就好了
P a y   A t t e n t i o n ! \color{red}Pay\ Attention!
当我在整个不等式中除以 b b 时,我相当于默认了 b ̸ = 0 b\not=0 ,但是如果 b = 0 b=0 ,这个算法算出的答案就错了
所以这里一定要单独讨论(WA了5发)

代码

//扩展欧几里德
#include <bits/stdc++.h>
#define ll long long
#define eps 1e-8
using namespace std;
ll read(ll x=0)
{
	ll c, f=1;
	for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
	return f*x;
}
ll gcd(ll a, ll b){return !b?a:gcd(b,a%b);}
void exgcd(ll a, ll b, ll &x, ll &y)
{
	if(b==0){x=1, y=0;return;}
	ll xx, yy;
	exgcd(b,a%b,xx,yy);
	x=yy, y=xx-a/b*yy;
}
ll work()
{
	ll a, b, c, g, x0, y0, x1, y1, x2, y2;
	double l, r, tmp;
	scanf("%lf",&tmp), x1=tmp*10;
	scanf("%lf",&tmp), y1=tmp*10;
	scanf("%lf",&tmp), x2=tmp*10;
	scanf("%lf",&tmp), y2=tmp*10;
	a=y1-y2, b=x2-x1, c=-x1*y2+x2*y1;
	if(b==0)
	{
		if(x1%10!=0)return 0;
		if(y1*y2<0)return abs(y1)/10+abs(y2)/10+1;
		return max(abs(y1),abs(y2))/10-min(abs(y1)-1,abs(y2)-1)/10;
	}
	g=gcd(a,b);
	if(c%(10*g)!=0)return 0;
	exgcd(10*a,10*b,x0,y0);
	l=0.1*(x1-x0*c/g)*g/b;
	r=0.1*(x2-x0*c/g)*g/b;
	if(l>r+eps)swap(l,r);
	return (ll)(floor(r+eps)-ceil(l-eps)+1);
}
int main()
{
	ll T=read();
	while(T--)printf("%lld\n",work());
	return 0;
}

猜你喜欢

转载自blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/83614597
今日推荐