1.题目描述:点击打开链接
2.解题思路:本题利用Pick定理解决。Pick定理讲的是:给定一个顶点都是整点的简单多边形,其面积A,内部格点的数目I与边上的格点数目B的关系是:A=I+B/2-1。这样,我们就能算出I=A-B/2+1。不过,这样并不能完整的解决本题,因为题目中要求计算每个小菱形的中点有多少个。由于错切变换不会影响内部格点的个数,因此我们不妨仍然理解为在相互垂直的x-y坐标系中,那么等价于要我们找内部x,y坐标的小数部分都是0.5的点有多少个。此时我们可以想办法把它们也都变成“整点”。最直观的办法就是将坐标系顺时针旋转45度,这样,原来的整点还是整点,小数部分均为0.5的点也成了整点。因此,我们可以统计在原坐标系下的内部整点数,再统计坐标系旋转后的内部整点数,后者减去前者就是答案。
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define me(s) memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long LL;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;
const double PI = acos(-1.0);
struct Point
{
int x, y;
Point(int x=0, int y=0):x(x),y(y) { }
};
typedef Point Vector;
Vector operator + (const Vector& A, const Vector& B) { return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (const Point& A, const Point& B) { return Vector(A.x-B.x, A.y-B.y); }
double Cross(const Vector& A, const Vector& B) { return (LL)A.x*B.y - (LL)A.y*B.x; }
LL PolygonArea2(const vector<Point>& p) //计算多边形面积*2的结果
{
int n = p.size();
LL area2 = 0;
for(int i = 1; i < n-1; i++)
area2 += Cross(p[i]-p[0], p[i+1]-p[0]);
return abs(area2);
}
inline int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a%b);
}
LL count_on_segment(const Point& a, const Point& b)//计算线段a-b上整点的个数,如果不计算端点,就是gcd(dx,dy)-1个,这不难通过参数表达式得到
{
return gcd(abs(b.x-a.x), abs(b.y-a.y)) - 1;
}
LL count_inside_polygon(const vector<Point>& poly) //利用Pick定理可得:I=A-B/2+1
{
int n = poly.size();
LL A2 = PolygonArea2(poly);
int B = n;
for(int i = 0; i < n; i++)
B += count_on_segment(poly[i], poly[(i+1)%n]);
return (A2 - B) / 2 + 1;//注意:这里的A2是多边形面积*2的结果,因此也要除以2
}
LL count(const vector<Point>& poly) //查找x,y小数部分都是0.5的点
{
vector<Point> poly2;
for(int i = 0; i < poly.size(); i++)
poly2.push_back(Point(poly[i].x-poly[i].y, poly[i].x+poly[i].y));
return count_inside_polygon(poly2) - count_inside_polygon(poly); //相减就是答案
}
int main()
{
int d, theta, N, x, y; //这里给定的d,theta只是用来计算面积的,错切变换后相当于x-y坐标系下的面积乘以系数d*d*sin(theta)
while(scanf("%d%d%d", &d, &theta, &N) == 3 && d)
{
vector<Point> poly;
for(int i = 0; i < N; i++) {
scanf("%d%d", &x, &y);
poly.push_back(Point(x, y));
}
LL area2 = PolygonArea2(poly);
printf("%lld %.0lf\n", count(poly), sin((double)theta / 180 * PI) * d * d * area2 / 2.0);//area2/2才是原坐标系的面积
}
return 0;
}