<题目链接>

<转载于 >>>  >

题目大意:

在二维平面上给出n条不共线的线段(线段端点是整数),问这些线段总共覆盖到了多少个整数点。

解题分析:

用GCD可求的某条给定线段上有多少个整数点,理由如下:

GCD(n,m)为n与m的最大公约数,通过辗转相除法求得。令g=GCD(n,m); n=x*g, m=y*g.所以将横坐标分为g个x份,将纵坐标分为g个y份。所以,本题线段覆盖的整数点个数为 g+1 (因为包含端点,如果不包含端点就为 g-1 )。

但是这样求的的覆盖点数是包含重复点数的,所以我们可以对每条线段再遍历一次,求的它与它之后线段的不重复交点个数,然后用总的交点个数减去这些重复计算的交点,就是答案了。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define eps 1e-6
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Fore(i,a,b) for(int i=a;i>=b;i--)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define mkp make_pair
#define pb push_back
#define sz size()
#define met(a,b) memset(a,b,sizeof(a))
#define iossy ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) //提高cin、cout的效率
#define fr freopen
#define pi acos(-1.0)
#define Vector Point
typedef pair<int,int> pii;
const long long linf=1LL<<;
const int iinf=<<;
const double dinf=1e17;
const int Mod=1e9+;
typedef long long ll;
typedef long double ld;
const int maxn=;
int n;
struct Point{
ll x,y;
int id;
Point(ll x=,ll y=):x(x),y(y) {}
Point operator - (const Point &a)const { return Point(x-a.x,y-a.y);}
bool operator == (const Point &a)const { return x==a.x && y==a.y; }
}; ll gcd(ll a,ll b){
while(b>){
ll t=b;b=a%b;a=t;
}
return a;
} ll Cross(Vector a,Vector b){ //向量叉乘
return a.x*b.y-a.y*b.x;
}
ll Dot(Vector a,Vector b) { //向量相乘
return a.x*b.x+a.y*b.y;
}
bool onsg(Point p,Point a1,Point a2){ //判断点p是否在a1,a2组成的线段上
return Cross(a1-p,a2-p)== && Dot(a1-p,a2-p)<;
//共线且反向
}
void ck(ll &c){
if(c>) c=;
else if(c<) c=-;
}
int Ins(Point a1,Point a2,Point b1,Point b2){ //判断两个线段是否有交点
if(a1==b1 || a1==b2 || a2==b1 || a2==b2) return ; //如果有端点相等,那么线段必然有交点
if(onsg(a1,b1,b2) || onsg(a2,b1,b2) || onsg(b1,a1,a2) || onsg(b2,a1,a2)) return ; //如果有端点在另一条线段上,那么这两条线段必然有交点 ll c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1); //用c1*c2<0来判断b1,b2是否在a1~a2线段的两边 ll c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1); //用c3*c4<0来判断a1,a2是否在b1~b2线段的两边
ck(c1);ck(c2);ck(c3);ck(c4);
return c1*c2< && c3*c4<;
} set<pair<ll,ll> >c;
void chk(Point p,Vector v,Point q,Vector w){ //找到两条线段的交点坐标
Vector u=p-q;
ll v1=Cross(w,u),v2=Cross(v,w);
if(abs(v1*v.x)%v2!= || abs(v1*v.y)%v2!=) return ;
ll xx,yy;
xx=p.x+v.x*v1/v2;yy=p.y+v.y*v1/v2;
c.insert(mkp(xx,yy));
} struct segm{
Point p1,p2;
}; segm ss[maxn];
Point p1,p2;
void solve(){
iossy;
cin>>n;
int ans=;
For(i,,n){
cin>>p1.x>>p1.y>>p2.x>>p2.y;
ss[i].p1=p1;ss[i].p2=p2;
ans+=gcd(abs(ss[i].p2.x-ss[i].p1.x),abs(ss[i].p2.y-ss[i].p1.y))+; //此处也可以直接用 __gcd()函数
}//利用gcd找出所有线段所能覆盖的整数点的总数 For(i,,n){
c.clear(); //每次清空set
For(j,i+,n){
int ct=Ins(ss[i].p1,ss[i].p2,ss[j].p1,ss[j].p2);
if(ct) chk(ss[i].p1,ss[i].p2-ss[i].p1,ss[j].p1,ss[j].p2-ss[j].p1);
//如果线段i与线段j有交点的话,将线段i与线段i+1~n的所有不重复的整数交点个数找出来
}
ans-=c.sz;
}
cout<<ans<<endl;
} int main(){
solve();
return ;
}

  

2018-09-09

Codeforces 1036E Covered Points (线段覆盖的整点数)【计算几何】的更多相关文章

  1. Codeforces 1036E. Covered Points

    又一次写起了几何.... 特殊处理在于有可能出现多条线段交于一点的情况,每次考虑时,对每条线段与其他所有线段的交点存在一个set里,对每一个set,每次删除set.size()即可 重点在于判断两条线 ...

  2. CodeForces 1000C Covered Points Count(区间线段覆盖问题,差分)

    https://codeforces.com/problemset/problem/1000/C 题意: 有n个线段,覆盖[li,ri],最后依次输出覆盖层数为1~n的点的个数. 思路: 区间线段覆盖 ...

  3. codeforces 1000C - Covered Points Count 【差分】

    题目:戳这里 题意:给出n个线段,问被1~n个线段覆盖的点分别有多少. 解题思路: 这题很容易想到排序后维护每个端点被覆盖的线段数,关键是端点值不好处理.比较好的做法是用差分的思想,把闭区间的线段改为 ...

  4. C - Covered Points Count CodeForces - 1000C (差分,离散化,统计)

    C - Covered Points Count CodeForces - 1000C You are given nn segments on a coordinate line; each end ...

  5. EDU 50 E. Covered Points 利用克莱姆法则计算线段交点

    E. Covered Points 利用克莱姆法则计算线段交点.n^2枚举,最后把个数开方,从ans中减去. ans加上每个线段的定点数, 定点数用gcs(△x , △y)+1计算. #include ...

  6. Educational Codeforces Round 46 C - Covered Points Count

    C - Covered Points Count emmm 好像是先离散化一下 注意 R需要+1 这样可以确定端点 emmm 扫描线?瞎搞一下? #include<bits/stdc++.h&g ...

  7. Covered Points Count CF1000C 思维 前缀和 贪心

     Covered Points Count time limit per test 3 seconds memory limit per test 256 megabytes input standa ...

  8. CODEVS3037 线段覆盖 5[序列DP 二分]

    3037 线段覆盖 5   时间限制: 3 s   空间限制: 256000 KB   题目等级 : 钻石 Diamond 题解       题目描述 Description 数轴上有n条线段,线段的 ...

  9. CODEVS1643 线段覆盖3[贪心]

    1643 线段覆盖 3   时间限制: 2 s   空间限制: 256000 KB   题目等级 : 黄金 Gold 题解       题目描述 Description 在一个数轴上有n条线段,现要选 ...

随机推荐

  1. checkstyle.xml Code Style for Eclipse

    1. Code Templates [下载 Code Templates] 打开 Eclipse -> Window -> Preferences -> Java -> Cod ...

  2. SQL Server 数据恢复到指点时间点(完整恢复)

    SQL Server 数据恢复到指点时间点(完整恢复) 高文龙关注2人评论944人阅读2017-03-20 12:57:12 SQL Server 数据恢复到指点时间点(完整恢复) 说到数据库恢复,其 ...

  3. Java 8 中的 Lambda 表达式

    Lambda 表达式是 Java 8 最受欢迎的功能.人们将函数式编程的概念引入了 Java 这门完全面向对象的命令式编程语言. 关于函数式编程是如何运作的,这个话题超出了本文的范围,不过我们会提炼出 ...

  4. LeetCode(89):格雷编码

    Medium! 题目描述: 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印格雷码序列.格雷码序列必须以 0 开头. 例如,给定 ...

  5. laravel Blade 模板引擎

    与视图文件紧密关联的就是模板代码,我们在视图文件中通过模板代码和 HTML 代码结合实现视图的渲染.和很多其他后端语言不同,PHP 本身就可以当做模板语言来使用,但是这种方式有很多缺点,比如安全上的隐 ...

  6. Java 11 这 8 个逆天新特性教你写出更牛逼的代码!

    美国时间2018年 09 月 25 日,Oralce 正式发布了 Java 11,这是据 Java 8 以后支持的首个长期版本. 为什么说是长期版本,看下面的官方发布的支持路线图表. 可以看出 Jav ...

  7. 无废话-API-01

    说明 我的开发环境:VS2013 浏览器:谷歌浏览器(Google Chrome) 1创建项目 1.1添加一个 应用程序"ASP.NET MVC 4 Web 应用程序"  1.2选 ...

  8. python文件操作r+,w+,a+,rb+,

    w:以写方式打开, a:以追加模式打开 (从 EOF 开始, 必要时创建新文件) r+:以读写模式打开 w+:以读写模式打开 (参见 w ) a+:以读写模式打开 (参见 a ) rb:以二进制读模式 ...

  9. OpenCV-Python入门教程7-PyQt编写GUI界面

    前面一直都是使用命令行运行代码,不够人性化.这篇用Python编写一个GUI界面,使用PyQt5编写图像处理程序.包括:打开.关闭摄像头,捕获图片,读取本地图片,灰度化和Otsu自动阈值分割的功能. ...

  10. 让simplejson支持datetime类型的序列化

    simplejson是Python的一个json包,但是觉得有点不爽,就是不能序列化datetime,稍作修改就可以了: 原文:http://blog.csdn.net/hong201/article ...