列表

详情


NC20303. [SCOI2015]小凸想跑步

描述

小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏。 
操场是个凸n边形,N个顶点按照逆时针从0~n-1编号。
现在小凸随机站在操场中的某个位置,标记为 P点。将P点与n个顶点各连一条边,形成N个三角形。如果这时P点,0号点,1号点形成的三角形的面 积是N个三角形中最小的一个,小凸则认为这是一次正确站位。 
 现在小凸想知道他一次站位正确的概率是多少。

输入描述

第1行包含1个整数n,表示操场的顶点数和游戏的次数。
接下来有N行,每行包含2个整数Xi,Yi表示顶点的坐标。 
输入保证按逆时针顺序输入点,所有点保证构成一个n多边形。
所有点保证不存在三点共线。

输出描述

输出1个数,正确站位的概率,保留4位小数。

示例1

输入:

5
1 8
0 7
0 0 
8 0
8 8

输出:

0.6316

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 481ms, 内存消耗: 35692K, 提交时间: 2022-03-27 14:17:03

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
using ldouble=long double;
const ldouble e=1e-10;
#define SI static inline
SI int tri_compare(ldouble x) {return fabs(x)<=e?0:x>e?1:-1;}
struct Point {
	ldouble x,y;
};
#define x1 A.x
#define y1 A.y
#define x2 B.x
#define y2 B.y
SI Point operator+(Point A, Point B){ return {x1+x2,y1+y2}; }
SI Point operator-(Point A, Point B){ return {x1-x2,y1-y2}; }
SI Point operator*(ldouble K, Point A){ return {K*x1,K*y1}; }
SI Point Vec(Point A, Point B){ return B-A; } /// gai
SI ldouble dot  (Point A, Point B){ return x1*x2 + y1*y2; }
SI ldouble cross(Point A, Point B){ return x1*y2 - x2*y1; }
#undef x1
#undef x2
#undef y1
#undef y2

struct Line {
	Point A;
	Point B;
	ldouble Arg=100;
	Point vec(){ return Vec(A,B); } // v
	ldouble arg(){
		if(Arg<50) return Arg;
		return Arg=atan2(vec().y,vec().x);
	}
};
SI bool operator<(Line m, Line n){ return m.arg()<n.arg(); }

SI bool OnLeft(Line L, Point A){ return tri_compare(cross(L.vec(),Vec(L.A,A)))>=0; }

SI Point intersection(Line a,Line b) {
    Point u=Vec(a.A,b.A);
    ldouble t=cross(u,b.vec())/cross(a.vec(),b.vec());
    return a.A+t*a.vec();
}

ldouble Area(Point* A, int n)
{
	ldouble ans=0;
	for(int i=0; i<n; i++) ans+=cross(A[i],A[(i+1)%n]);
	return ans/2;
}

int HalfplaneIntersection(Line* L, int n, Point* poly)
{
	stable_sort(L,L+n);
	int first=0,last=0;
	static Point p[maxn];
	static Line q[maxn+5];
	q[last]=L[0];
	for(int i=1; i<=n; i++) {
		while(first<last&&!OnLeft(L[i],p[last-1]))last--;
		while(first<last&&!OnLeft(L[i],p[first]))first++;
		q[++last]=L[i];
		if(first<last)p[last-1]=intersection(q[last-1],q[last]);
	}
	while(first<last&&!OnLeft(q[first],p[last-1]))last--;
	if(last-first<=1)return 0;
	p[last]=intersection(q[last],q[first]);
	int m=0;
	for(int i=first; i<=last; i++) poly[m++]=p[i];
	return m;
}
Point A[maxn],ans[maxn];
Line L[maxn];
int main() {
	int n,cnt=0;
	scanf("%d",&n);
	for(int i=0; i<n; i++) {
		scanf("%Lf",&A[i].x);
		scanf("%Lf",&A[i].y);
	}
	A[n]=A[0];
	for(int i=0; i<n; i++)L[cnt++]={A[i],A[i+1]};
	for(int i=1; i<n; i++) {
		ldouble a=A[1].y-A[0].y-A[i+1].y+A[i].y,b=A[0].x-A[1].x-A[i].x+A[i+1].x,c=A[1].x*A[0].y-A[0].x*A[1].y-A[i+1].x*A[i].y+A[i].x*A[i+1].y;
		if(tri_compare(b)) L[cnt++]={{0,-c/b},{b,-a-c/b}};
		else if(tri_compare(a)) L[cnt++]={{-c/a,0},{-c/a,-a}};
	}
	int tot=HalfplaneIntersection(L,cnt,ans);
	printf("%0.4Lf\n",Area(ans,tot)/Area(A,n));
}





















上一题