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 }

 

posted @ 2017-04-23 20:33  Dilthey  阅读(297)  评论(0编辑  收藏  举报