UVa 11768 格点判定(扩展欧几里得求线段整点)

https://vjudge.net/problem/UVA-11768

题意:

给定两个点A(x1,y1)和B(x2,y2),均为0.1的整数倍。统计选段AB穿过多少个整点。

思路:

做了这道题之后对于扩展欧几里得有了全面的了解。

根据两点式公式求出直线 ,那么ax+by=c 中的a、b、c都可以确定下来了。

接下来首先去计算出一组解(x0,y0),因为根据这一组解,你可以写出它的任意解,其中,K取任何整数。

需要注意的是,这个 a‘ 和 b‘ 是很重要的,比如说 b‘ ,它代表的是x每隔 b‘ ,就会出现一个整点。

所以这道题目的关键就是,我们先求出一组解,然后通过它的 b‘ 将x0改变成x,使得x在[x1,x2]区间之内,这样每 b‘ 个单位就有一个整点了,即

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<stack>
 7 #include<queue>
 8 #include<cmath>
 9 #include<map>
10 using namespace std;
11
12 typedef long long LL;
13 double X1,Y1,X2,Y2;
14
15 void gcd(LL a,LL b,LL& d,LL& x,LL& y)
16 {
17     if(!b)  {d=a;x=1;y=0;}
18     else { gcd(b,a%b,d,y,x); y-=x*(a/b);}
19 }
20
21 LL solve()
22 {
23     LL x1=X1*10, y1=Y1*10, x2=X2*10, y2=Y2*10;
24     if(x1==x2)                    //平行y轴
25     {
26         if(x1%10)  return 0;      //原来的X1为小数,肯定不是整点
27         if(Y2<Y1)  swap(Y1,Y2);
28         return floor(Y2)-ceil(Y1)+1;
29     }
30     if(y1==y2)
31     {
32         if(y1%10)  return 0;
33         if(X2<X1)  swap(X1,X2);
34         return  floor(X2)-ceil(X1)+1;
35     }
36     LL a=(y2-y1)*10, b=(x1-x2)*10, c=y2*x1-y1*x2;  //c相当于扩大了100倍,所以前面还得乘10
37     LL d,x,y;
38     gcd(a,b,d,x,y);
39     if(c%d)   return 0;      //扩展欧几里得算法无解的判断
40
41     x=x*c/d; y=y*c/d;        //获得一组整数解(x,y)
42     b=abs(b/d);             //这里的b其实就是b‘
43
44     if(X1>X2)   swap(X1,X2);
45     x1=ceil(X1);
46     x2=floor(X2);
47     if(x1>x2) return 0;
48
49     x=x+(x1-x)/b*b;        //使x进入[x1,x2]的区间内
50     if(x<x1)  x+=b;
51     if(x>x2)  return 0;
52     return (x2-x)/b+1;
53 }
54
55 int main()
56 {
57     //freopen("D:\\input.txt","r",stdin);
58     int T;
59     scanf("%d",&T);
60     while(T--)
61     {
62         scanf("%lf%lf%lf%lf",&X1,&Y1,&X2,&Y2);
63         LL ans = solve();
64         printf("%lld\n",ans);
65     }
66     return 0;
67 }
时间: 2024-07-30 10:09:19

UVa 11768 格点判定(扩展欧几里得求线段整点)的相关文章

扩展欧几里得求最小非负整数解 (POJ 1061 青蛙约会为例)

Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的.但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的.为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面. 我们把这

[ACM] POJ 1061青蛙的约会(扩展欧几里得求模线性方程)

青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 89206   Accepted: 15926 Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能

UVA 12169 Disgruntled Judge 枚举+扩展欧几里得

题目大意:有3个整数 x[1], a, b 满足递推式x[i]=(a*x[i-1]+b)mod 10001.由这个递推式计算出了长度为2T的数列,现在要求输入x[1],x[3],......x[2T-1], 输出x[2],x[4]......x[2T]. T<=100,0<=x<=10000. 如果有多种可能的输出,任意输出一个结果即可. 由于a和b都小于等于10000,直接枚举a和b暴力可以过.但是有没有更快的方法呢? 首先令递推式的i=2,那么x[2]=(a*x[1]+b)mod 1

hdu_1576A/B(扩展欧几里得求逆元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1576 A/B Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4020    Accepted Submission(s): 3091 Problem Description 要求(A/B)%9973,但由于A很大,我们只给出n(n=A%99

暑期学习日记二—利用扩展欧几里得求逆元

最近学习了扩展欧几里得和乘法逆元的关系,在这里写一下巩固一下记忆 扩展欧几里得是什么呢,在这就不详解了,可以自行百度,主要来说,对于 求解ax ≡ 1(mod n)来说,当gcd(a,n)=1时,证明逆元存在,若不等于1,则证明逆元不存在. 那么当逆元存在时,我们要如何求它的逆元呢? 首先是扩展欧几里得定理,先将式子转换成 ax-ny = 1 的形式,然后我们要通过扩展欧几里得定律去获得它的最大公约数,还有它的一组解 X0,Y0 1 int exgcd(int a, int b, int &x,

hdu1576 A/B 扩展欧几里得求逆元

//(a/b)%c ==> a%c = (b*k) %c; // k = (a*(b_1))%c ,b_1为b的逆元 #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int mod = 9973 ; typedef __int64 ll; int exgcd(int a ,int b , ll &x ,ll &y) { if(b ==

HDU1576(扩展欧几里得)

A/B Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4252    Accepted Submission(s): 3277 Problem Description 要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1). Input 数据的第一行是一个T

poj1061--青蛙的约会--扩展欧几里得

Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的.但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的.为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面. 我们把这

UVALive 6428 A+B 【扩展欧几里得】

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4439 题目大意:给出a,b,S三个数,每次可以选择从a的位置加到b上,也可以从b的位置加到a上,问a或者b的位置上能否达到S. 比如:给出a和b,可以得到的是 (a b) (a+b b) (a a+b) (a+2b b)   (a+b a+2*b)     (2a+