链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2868
题解
这题本身不难,但是边界情况容易造成
W
A
\color{red}WA
WA
我先把坐标读入进来并且乘以
10
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
(y1−y2)x+(x2−x1)y=x2y1−x1y2
用字母代替系数,得到直线方程
a
x
+
b
y
=
c
ax+by=c
ax+by=c
现在就是要找横纵坐标都是
10
10
10的倍数的点,其个数就是答案
解不定方程
10
a
x
+
10
b
y
=
c
10ax+10by=c
10ax+10by=c,
x
∈
[
x
1
,
x
2
]
x\in[x_1,x_2]
x∈[x1,x2],解的个数就是答案
如果
(
10
(
a
,
b
)
)
̸
∣
c
(10(a,b))\not|c
(10(a,b))̸∣c,方程无解,点数是
0
0
0
否则解
10
a
x
′
+
10
b
y
′
=
(
10
a
,
10
b
)
10ax'+10by'=(10a,10b)
10ax′+10by′=(10a,10b)
假设解出一组
x
′
=
x
0
,
y
′
=
y
0
x'=x_0,y'=y_0
x′=x0,y′=y0
解集构造为
x
=
x
0
c
(
10
a
,
10
b
)
+
k
b
(
a
,
b
)
x=x_0\frac{c}{(10a,10b)}+k\frac{b}{(a,b)}
x=x0(10a,10b)c+k(a,b)b
而
10
x
∈
[
x
1
,
x
2
]
10x\in[x_1,x_2]
10x∈[x1,x2]
即
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
0.1x1≤x0(10a,10b)c+k(a,b)b≤0.1x2
解得
(
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)})
b(a,b)(0.1x1−x0(10a,10b)c)≤k≤b(a,b)(0.1x2−x0(10a,10b)c)
利用取整函数求出
k
k
k的个数就好了
P
a
y
A
t
t
e
n
t
i
o
n
!
\color{red}Pay\ Attention!
Pay Attention!
当我在整个不等式中除以
b
b
b时,我相当于默认了
b
̸
=
0
b\not=0
b̸=0,但是如果
b
=
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;
}