解题报告——直线整点数量问题总结

24 篇文章 0 订阅
24 篇文章 0 订阅

直线整点问题,例题(NEUQOJ改编):扩展欧几里得算法的应用。

二维空间之旅

时间限制(普通/Java:1000MS/2000MS空间限制:65536Kbyte

通过:23   总提交:127

描述

有一天jhjjhj不小心掉入了二维空间,在这个二维空间中,jhjjhj感觉很是惬意,他一会儿在直线上跳舞,一会儿又从很多个同心圆中穿过,一会又在一个大正方形里面和一群小线段玩捉迷藏,很是惬意。玩着玩着,jhjjhj忘记了时间,他突然想起,虽然二维空间也是这样美好,但是自己还是要返回三维空间的,但是自己现在为止还不知道如何返回自己的世界,于是向优美的心形女王求助。心形女王告诉他,返回三维空间的大门被一条直线(直线方程是ax+by=c)守卫,而返回三维空间的唯一方法就是点亮某一范围内直线所在整点的宝石。现在,jhjjhj想知道到底在这个范围内有多少个整点呢?焦急万分的jhjjhj已经开始抓耳挠腮,失去了思考能力了,所以通过时空电话向聪明的你进行求助,你能帮帮他吗?

输入

输入的第一行是一个整数T,表示测试案例的数量。接下来有2T行中,每组测试案例包括两行,第一行包括三个正整数a,b,c,第二行包括四个整数x1,x2,y1,y2-100<=x1,x2,x3,x4<=100)。

输出

对于每组测试案例,输出一个整数,表示直线ax+by=cx属于[x1,x2]y属于[y1,y2]上,有多少的整点在该直线上。

样例输入

2

3 6 3

-1 1 -1 1

3 5 6

-10 10 -10 10

样例输出

2

4

直线上的点:求直线ax+by=c上有多少个整点(x,y)满足x属于[x1,x2]y属于[y1,y2]

算法:欧几里得算法。

算法功能:获得整数a,b的最大公约数。

代码:

intgcd(int a,int b) {return !b?a:gcd(b,a%b);}

算法:扩展欧几里得算法。

算法功能:找出一对儿整数解(x,y),使得ax+by=gcd(a,b),其中gcd(a,b)表示a,b的最大公约数。

代码:

voidextra_gcd(int a,int b,int &x,int &y)

{

if(!b) {x=1;y=0;}

else {extra_gcd(b,a%b,y,x);y-=x*(a/b);}

}

定理1:设a,b,c为任意整数,g=gcd(a,b),若方程ax+by=c的一组整数解为(x0,y0),则它的任意整数解可以表示为(x0+kb’,y0-ka’)。其中a’=a/gb’=b/gk取任意整数。

特别说明:以上定理假设gcd(a,b)不等于0。当gcd(a,b)=0时,a,b至少有一个为0,这种情况特殊讨论。

定理1的证明:

假设ax+by=g的一组解为(x1,y1)且已得出,而进一步假设我们知道另外一组解为(x2,y2),则有ax1+by1=gax2+by2=g

则:ax1+by1=ax2+by2

得:a(x1-x2)=b(y2-y1)g=gcd(a,b)

方程两边同时除以g,得a’(x1-x2)=b’(y2-y1)

易得a’b’互素,所以x1-x2必为b’的整数倍,这样才能保证等式成立。

假设x1-x2=kb’,则有x1=x2+kb’

而将x1-x2=kb’带入方程,a’kb’=b’(y2-y1),易得:y2-y1=ka’,即y1=y2-ka’

由于以上推论与等式右边的c值无关

故,定理1得证。

定理2:若方程ax+by=g的一组整数解为(x0,y0),那么方程ax+by=c的整数解为(x0*c/g,y0*c/g)。特别说明:当c/g不为整数时,ax+by=c无整数解。

定理2的证明:

若方程ax+by=g的一组整数解为(x0,y0),则有ax0+by0=g

两边同时除以g,所以有a/gx0+b/gy0=1,即(x0,y0)a’x+b’y=1的整数解。

两边同时乘以c,得a(c*x0/g)+b(c*y0/g)=c,即(x0*c/g,y0*c/g)是方程ax+by=c的整数解

故,定理2得证。

对于直线上正点数量问题的解题步骤:

1)根据欧几里得算法算出g=gcd(a,b)。进而计算出a’=a/gb’=b/g

2)由扩展欧几里得算法算出满足ax+by=g的一对儿整数解(x0,y0),由定理2知,满足ax+by=c的一对儿整数解为(x0*c/g,y0*c/g)。当c/g不为整数时,该问题无解。

3)由定理1可知ax+by=c的任意整数解可以写作(x0*c/g+k*b/g,y0*c/g-k*a/g)

x0*c/g+k*b/g属于[x1,x2],可以解得k的一个范围(前后适当取整),由y0*c/g-k*a/g属于[y1,y2]可以解得另一个k的范围,两个范围取交集,得k属于[k1,k2],故整点个数为k2-k1+1个。

程序代码如下(C++

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

int gcd(int x,int y) {return!y?x:gcd(y,x%y);}     //欧几里得算法

void gcd(int a,int b,int &x,int &y)      //扩展欧几里得算法

{

         if(!b){x=1;y=0;}

         else {gcd(b,a%b,y,x);y-=x*(a/b);}

}

int max(int x,int y) {return x>y?x:y;}     //最大值算法

int min(int x,int y) {return x<y?x:y;}     //最小值算法

int main()

{

         intT,a,b,c,x1,x2,y1,y2;

         intaa,bb,g,x0,y0;

         intlx,rx,ly,ry;

         while(~scanf("%d",&T))

         {

                   while(T--)

                   {

                            scanf("%d%d%d",&a,&b,&c);

                            scanf("%d%d%d%d",&x1,&x2,&y1,&y2);

                            g=gcd(a,b);

                            aa=a/g;

                            bb=b/g;

                            gcd(a,b,x0,y0);

                            if(c%g==0)

                            {

                                     x0*=c/g;

                                     y0*=c/g;

                                     lx=(x1-x0)/bb;

                                     rx=(x2-x0)*1.0/bb-0.99999999;   //对于下界,向上取整

                                     ly=(y0-y2)/aa;

                                     ry=(y0-y1)*1.0/aa-0.99999999;   //对于下界,向上取整

                                     if(rx<ly||ry<lx) printf("0\n");

                                     else

                                     {

                                               lx=max(lx,ly);

                                               rx=min(rx,ry);

                                               printf("%d\n",rx-lx+1);

                                     }

                            }

                            else printf("0\n");

                   }

         }

         return 0;

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值