UVA 11768 - Lattice Point or Not
首先本题需要用到扩展欧几里得算法……
关于exgcd算法的一点简略证明:
那么,对于函数exgcd(a,b)=(d,x,y),其中d满足d=gcd(a,b); (x,y)满足ax+by=d;
则exgcd(b,a mod b)=(d,x',y'),而此时,使用 x = y' ; y = x' - floor(a/b) * y' = x' - floor(a/b) * x 就能得到exgcd(a,b)的值。
故我们可以有扩展欧几里得算法如下:
void exgcd(int a,int b,int &d,int &x,int &y){ if(!b){d=a;x=1;y=0;} else {exgcd(b,a%b,d,y,x);y-=(a/b)*x;} }
此处的边界条件是exgcd(a,0)=(a,1,0)
那么此时,若c mod gcd(a,b) = 0,就容易求得一个整点(x,y),那么如何得到所有的点?
然后是题目的代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 typedef long long ll; 7 using namespace std; 8 void exgcd(ll a,ll b,ll &d,ll &x,ll &y){ 9 if(!b){d=a;x=1;y=0;} 10 else {exgcd(b,a%b,d,y,x);y-=(a/b)*x;} 11 } 12 int main() { 13 double X1,Y1,X2,Y2; 14 int t; 15 scanf("%d",&t); 16 while(t--){ 17 scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);//获得初始坐标(x1,y1),(x2,y2) 18 ll x1=X1*10,x2=X2*10,y1=Y1*10,y2=Y2*10;//将坐标都换成整型 19 if(x1==x2)//如果这条线是一条竖直的线 20 { 21 if(x1%10!=0){//如果此时的直线l:x=c,c不是整数,那么这条线上显然没有整点 22 printf("0\n"); 23 continue; 24 } 25 y2=floor(max(Y1,Y2)); 26 y1=ceil(min(Y1,Y2)); 27 printf("%lld\n",y2-y1+1); 28 continue; 29 } 30 if(y1==y2)//如果这条线是一条水平的线 31 { 32 if(y1%10!=0){//如果此时的直线l:y=c,c不是整数,那么这条线上显然也没有整点 33 printf("0\n"); 34 continue; 35 } 36 x2=floor(max(X1,X2)); 37 x1=ceil(min(X1,X2)); 38 printf("%lld\n",x2-x1+1); 39 continue; 40 } 41 ll a=(y2-y1)*10,b=(x1-x2)*10,c=x1*y2-x2*y1;//计算出l:ax+by=c 42 ll x,y,d; 43 if(X2<X1) swap(X2,X1);//确保x2>x1 44 x1=ceil(X1),x2=floor(X2); 45 if(x1>x2){//如果一条线的斜率过大,使得x1,x2有m<x1<x2<m+1 (m为整数),那么显然这个范围内没有整点 46 printf("0\n"); 47 continue; 48 } 49 ll k=0; 50 exgcd(a,b,d,x,y);//得到满足ax+by=gcd(a,b)的(x0,y0) 51 if (c%d==0)//如果c是gcd(a,b)的整数倍,即c = k * gcd(a,b),那么显然点( k * x0 , k * y0 )是ax+by=c上的一个整点 52 { 53 a/=d,b/=d; 54 x*=c/d,y*=c/d; 55 if(b<0) b=-b; 56 x=x-(x-x1)/b*b; 57 while(x<x1) x+=b; 58 while(x+k*b<=x2) k++; 59 printf("%lld\n",k); 60 } 61 else printf("0\n"); 62 } 63 return 0; 64 }
转载请注明出处:https://dilthey.cnblogs.com/