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 |
这题好坑。。
一开始就有想法,先找到离上面端点最近的一个在直线上的整点,然后根据最小公倍数的循环节算出这个点到下端点之间有多少个。
小数乘以10,问题就变成了先找一个是10的倍数的点,把坐标带入得到方程(Y1-Y2)x+(X2-X1)y=Y1X2-Y2X1,把等号左边乘10变成10(Y1-Y2)x+10(X2-X1)y=Y1X2-Y2X1,用扩展gcd求出x,y,再乘以10,就成了10的倍数的解。这是个好方法~
后面求循环节就类似于一个矩形对角线上能经过多少个整点的问题,答案是每经过gcd(N,M)有一个。还要注意的是根据解的位置分情况求出离上端点最近的整点,还有各种特判。。呵呵呵。。。
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define eps 1e-9
#define MAXN 30010
#define MAXM 110
#define MOD 999983
typedef long long LL;
using namespace std;
int T;
double t1,t2,t3,t4;
LL X1,Y1,X2,Y2;
void extend_gcd(LL a,LL b,LL& d,LL& x,LL &y){
if(!b){
d=a;
x=1;
y=0;
}
else{
extend_gcd(b,a%b,d,y,x);
y-=a/b*x;
}
}
LL gcd(LL a,LL b){
return a%b?gcd(b,a%b):b;
}
LL lcm(LL a,LL b){
return a*b/gcd(a,b);
}
int get_one_reult(LL &x,LL &y){
LL d;
extend_gcd(10*(Y1-Y2),10*(X2-X1),d,x,y);
if((Y1*X2-Y2*X1)%d!=0) return 0;
x=10*x*(Y1*X2-Y2*X1)/d;
y=10*y*(Y1*X2-Y2*X1)/d;
return 1;
}
int main(){
freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%lf%lf%lf%lf",&t1,&t2,&t3,&t4);
if(t1>=0) X1=LL(t1*10+0.5);
else X1=LL(t1*10-0.5);
if(t2>=0) Y1=LL(t2*10+0.5);
else Y1=LL(t2*10-0.5);
if(t3>=0) X2=LL(t3*10+0.5);
else X2=LL(t3*10-0.5);
if(t4>=0) Y2=LL(t4*10+0.5);
else Y2=LL(t4*10-0.5);
if(Y1>Y2){
swap(X1,X2);
swap(Y1,Y2);
}
if(X1==X2&&Y1==Y2){
if(X1%10||Y1%10) printf("0\n");
else printf("1\n");
continue;
}
LL N=abs(X1-X2),M=abs(Y1-Y2),x,y,ans,ymin,xmin;
if(M==0){
if(Y1%10){
printf("0\n");
continue;
}
if(X1>X2) swap(X1,X2);
if(X1%10) xmin=X1+10-X1%10;
else xmin=X1;
if(xmin<=X2) ans=1+(X2-xmin)/10;
else ans=0;
printf("%lld\n",ans);
continue;
}
if(N==0){
if(X1%10){
printf("0\n");
continue;
}
if(Y1%10) ymin=Y1+10-Y1%10;
else ymin=Y1;
if(ymin<=Y2) ans=1+(Y2-ymin)/10;
else ans=0;
printf("%lld\n",ans);
continue;
}
if(!get_one_reult(x,y)){
printf("0\n");
continue;
}
LL d=gcd(N,M);
LL a=10/gcd(N/d,10),b=10/gcd(M/d,10),n=lcm(a,b),cirx=N/d*n,ciry=M/d*n;
if(y>Y1) ymin=Y1+(y-Y1)%ciry;
else{
if((Y1-y)%ciry) ymin=Y1+ciry-(Y1-y)%ciry;
else ymin=Y1;
}
xmin=(Y1*X2-Y2*X1+(X1-X2)*ymin)/(Y1-Y2);
if(X1<=X2){
if(xmin>=X1&&xmin<=X2) ans=1+(X2-xmin)/cirx;
else ans=0;
}
else{
if(xmin>=X2&&xmin<=X1) ans=1+(xmin-X2)/cirx;
else ans=0;
}
printf("%lld\n",ans);
}
return 0;
}