tyvj 1150 绳子围点 Pick定理 防溢出策略
背景 Background
最近小小鱼在研究平面几何,遇到一个难题,怎么也想不出来,于是找到大牛你来帮他做。描述 Description
给出平面上n个点,所有点的坐标都是整数,小小鱼用一条绳子围成一个封闭图形,把这些点全部围在里面,并且所用绳子长度最短。围好了之后,小小鱼想知道这条绳子总共围住了多少个横、纵坐标都为整数的点(包括给出的n个点和未给出的点,绳子刚好穿过的点也算围在内),但是数着满平面的点,小小鱼晕了过去>.<。输入格式 InputFormat
第一行一个整数n(n<=200000),表示给出点的个数。以下n行每行两个整数xi,yi(都在longint范围内),表示给出第i个点的坐标。
输出格式 OutputFormat
一行,一个整数,表示绳子所围住的横纵坐标都为整数的顶点个数。样例输入 SampleInput [复制数据]
4
-1 -1
1 3
3 1
1 1
样例输出 SampleOutput [复制数据]
10
数据范围和注释 Hint
样例中最短的绳子围法是三个顶点分别为(-1,-1),(3,1),(1,3)的三角形其中绳子围住了以下点:
(-1,-1),(0,0),(1,0),(0,1),(1,1),(2,1),(1,2),(2,2),(3,1),(1,3)
总共10个。
答案可能超过longint的范围,需要用int64或long long。
来源 Source
小小鱼pick定理S=I+(A/2)-1;
s是面积,I是多边形内部整点,A是边上整点;
A 用GCD求,注意0的情况。
这道题是一道数据量极大,极易出现long long 溢出的题,下面就总结一下这类题要注意的:
- 两个[-1e9,1e9]内的int相减会溢出,主要出现再几何题中
- 如果在取模题目中,有减运算,注意最后要把他变成正数
- 1e9的数据范围忌用double
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 210000 #define eps 1e-9 #define LL "%lld" typedef long long qword; int gcd(int x,int y) { return (y==0)?x:gcd(y,x%y); } struct point { qword x,y; }pl[MAXN],seq[MAXN]; bool cmp(const point & p1,const point &p2) { if (p1.x==p2.x)return p1.y<p2.y; return p1.x<p2.x; } qword area(const point &p1,const point &p2,const point &p3) { return ((qword)(p1.x-p2.x)*(p1.y-p3.y)-(qword)(p1.y-p2.y)*(p1.x-p3.x)); } int main() { freopen("input.txt","r",stdin); int n; int i,j; scanf("%d",&n); for (i=0;i<n;i++) { scanf(LL LL,&pl[i].x,&pl[i].y); } sort(pl,&pl[n],cmp); seq[0]=pl[0]; seq[1]=pl[1]; int h=0; int top=1; for (i=2;i<n;i++) { while (top>h && area(seq[top-1],seq[top],pl[i])<=eps) { top--; } seq[++top]=pl[i]; } h=top; for (i=n-2;i>=0;i--) { while (top>h && area(seq[top-1],seq[top],pl[i])<=eps) { top--; } seq[++top]=pl[i]; } top--; /* for (i=0;i<=top;i++) { printf("(%d,%d)",seq[i].x,seq[i].y); }*/ qword S=0; int x,y; point tp; tp.x=tp.y=0; for (i=1;i<top;i++) { S+=area(seq[0],seq[i],seq[(i+1)%(top+1)]); } qword A=0; for (i=0;i<=top;i++) { x=seq[i].x-seq[(i+1)%(top+1)].x; y=seq[i].y-seq[(i+1)%(top+1)].y; x=abs(x); y=abs(y); if (!x)A+=y; else if (!y) A+=x; else A+=gcd(x,y); } //S=I+(A/2)-1 qword I; I=(S-A+2)/2; cout<<I+A<<endl;; }
by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载
本博客已停用,新博客地址:http://mhy12345.xyz