Gym 101873G - Water Testing - [皮克定理]

题目链接:http://codeforces.com/gym/101873/problem/G

 

题意:

在点阵上,给出 N 个点的坐标(全部都是在格点上),将它们按顺序连接可以构成一个多边形,求该多边形内包含的格点的数目。

 

题解:

首先,根据皮克定理 S=a+b21,其中 S 是多边形面积,a 是多边形内部格点数目,b 是多边形边界上的格点数目。

那么,我们只要求出 Sb,就很好求得 a 了:

1、对于两端点 (x1,y1),(x2,y2) 都再格点上的一条线段,该线段上的格点数目为 gcd(|x1x2|,|y1y2|)+1。这很好理解,对于横坐标差值和纵坐标差值求得的最大公因数 g,相当于将横坐标差值分成 g 份,由于是整除,因此显然每份的左右端点都是整数,对于纵坐标也是同样的道理,由于是最大公因数,所以不可能再分更多份,因此 gcd(|x1x2|,|y1y2|) 即求得两端点间最多能分成多少段由格点分割的线段,再加上 1 即整条线段上的格点数目。

2、对于格点按顺序给出的多边形,设 P0=Pn+1O 为原点,则面积为 12i=0n(OPi×OPi+1)。这个画个图模拟一下也非常容易理解。

 

AC代码:

复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int maxn=1e5+10;
int n;
pll p[maxn];
inline ll gcd(ll m,ll n){return n?gcd(n,m%n):m;}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++) scanf("%lld%lld",&p[i].first,&p[i].second);
    ll S2=0, b=0;
    for(int i=0;i<n;i++)
    {
        S2+=p[i].first*p[(i+1)%n].second-p[i].second*p[(i+1)%n].first;
        b+=gcd(abs(p[i].first-p[(i+1)%n].first),abs(p[i].second-p[(i+1)%n].second));
    }
    cout<<(abs(S2)-b+2)/2<<endl;
}
复制代码

 

posted @   Dilthey  阅读(802)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示