[Luogu P4250] [BZOJ 4445] [SCOI2015]小凸想跑步

洛谷傳送門

BZOJ傳送門

題目描述

小凸晚上喜歡到操場跑步,今天他跑完兩圈之後,他玩起了這樣一個遊戲。

操場是個凸 nn 邊形, nn 個頂點按照逆時針從 0n10 \sim n - 1 編號。現在小凸隨機站在操場中的某個位置,標記爲 pp點。將 pp 點與 nn 個頂點各連一條邊,形成 nn 個三角形。如果這時 pp 點, 00 號點, 11 號點形成的三角形的面 積是 nn 個三角形中最小的一個,小凸則認爲這是一次正確站位。

現在小凸想知道他一次站位正確的概率是多少。

輸入輸出格式

輸入格式:

11 行包含 11 個整數 nn, 表示操場的頂點數和遊戲的次數。

接下來有 nn 行,每行包含 22 個整數 xi,yix_i, y_i,表示頂點的座標。

輸入保證按逆時針順序輸入點,所有點保證構成一個凸多邊形。所有點保證不存在三點共線。

輸出格式:

輸出 11 個數,正確站位的概率,保留 44 位小數。

輸入輸出樣例

輸入樣例#1:

5
1 8
0 7
0 0
8 0
8 8

輸出樣例#1:

0.6316

說明

對於 30%30\% 的數據, 3n4,0x,y103 \leq n \leq 4, 0 \leq x, y \leq 10

對於 100%100\% 的數據, 3n105,109x,y1093 \leq n \leq 10^5, -10^9 \leq x, y \leq 10^9

解題分析

設一條邊兩端的兩個點爲Ai(xi,yi),Aj(xj,yj)A_i(x_i,y_i),A_j(x_j,y_j), 那麼面積爲
(xjxi)(ypyi)(yjyi)(xpxi)=xp(yiyj)+yp(xjxi)xjyi+xiyj (x_j-x_i)(y_p-y_i)-(y_j-y_i)(x_p-x_i) \\ =x_p(y_i-y_j)+y_p(x_j-x_i)-x_jy_i+x_iy_j
再加上SA0A1Ap<SAiAjApS\triangle A_0A_1A_p<S\triangle A_iA_jA_p這個限制, 可得:
xp(yiyjy0+y1)+yp(xjxix1+x0)+(xiyjxjyix0y1+x1y0)>0 x_p(y_i-y_j-y_0+y_1)+y_p(x_j-x_i-x_1+x_0)+(x_iy_j-x_jy_i-x_0y_1+x_1y_0)> 0
然後每個不等式都是一個半平面的形式, 搞搞半平面交就好了。

代碼如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define EPS 1e-8
#define db long double
#define MX 200500
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
int n, lcnt, h, t;
db all, area;
struct Point {db x, y;} dat[MX], inter[MX];
IN Point operator + (const Point &x, const Point &y) {return {x.x + y.x, x.y + y.y};}
IN Point operator - (const Point &x, const Point &y) {return {x.x - y.x, x.y - y.y};}
IN Point operator * (R db k, const Point &x) {return {x.x * k, x.y * k};}
IN db Getk(const Point &x) {return std::atan2(x.y, x.x);}
IN db operator * (const Point &x, const Point &y) {return x.x * y.y - x.y * y.x;}
struct Line {Point fr, to; db rat;} line[MX], que[MX];
IN bool operator < (const Line &x, const Line &y) {return x.rat < y.rat;}
IN Point GetInt(const Line &x, const Line &y)
{
	db k1 = (y.to - y.fr) * (x.to - y.fr);
	db k2 = (y.to - y.fr) * (x.fr - y.fr);
	return x.fr + (-k2 / (k1 - k2)) * (x.to - x.fr);
}
IN bool onleft(const Line &x, const Point &y)
{return (x.to - x.fr) * (y - x.fr) > EPS;}
IN int sig (R db x) {return (x > -EPS) - (x < EPS);}
IN db Getk(const Line &x) {return Getk(x.to - x.fr);}
int main(void)
{
	db a, b, c;
	Point fr, to;
	scanf("%d", &n);
	for (R int i = 0; i < n; ++i) scanf("%Lf%Lf", &dat[i].x, &dat[i].y);
	dat[n] = dat[0];
	for (R int i = 2; i < n; ++i) all += abs((dat[i - 1] - dat[0]) * (dat[i] - dat[0]) / 2);
	for (R int i = 1; i <= n; ++i) line[++lcnt] = {dat[i - 1], dat[i]};
	for (R int i = 1; i < n; ++i)
	{
		a = dat[i].y - dat[i + 1].y - dat[0].y + dat[1].y;
		b = dat[i + 1].x - dat[i].x - dat[1].x + dat[0].x;
		c = dat[i].x * dat[i + 1].y - dat[i + 1].x * dat[i].y - dat[0].x * dat[1].y + dat[1].x * dat[0].y;
		if (!sig(a))
		{
			db height = -c / b;
			fr = {0, height}, to = {1, height};
			if (b > 0) line[++lcnt] = {fr, to};
			else line[++lcnt] = {to, fr};
		}
		else if (!sig(b))
		{
			db wid = -c / a;
			fr = {wid, 0}, to = {wid, 1};
			if (a > 0) line[++lcnt] = {to, fr};
			else line[++lcnt] = {fr, to};
		}
		else
		{
			db frx, fry, tox, toy;
			frx = 0, fry = -c / b, fr = {frx, fry};
			tox = 1, toy = (-c - a) / b, to = {tox, toy};
			if (a + (toy - 1) * b > -c) line[++lcnt] = {to, fr};
			else line[++lcnt] = {fr, to};
		}
	}
	for (R int i = 1; i <= lcnt; ++i) line[i].rat = Getk(line[i]);
	std::sort(line + 1, line + 1 + lcnt);
	que[h = t = 0] = line[1];
	for (R int i = 2; i <= lcnt; ++i)
	{
		W (h < t && !onleft(line[i], inter[t - 1])) --t;
		W (h < t && !onleft(line[i], inter[h])) ++h;
		que[++t] = line[i];
		if (!sig((line[i].to - line[i].fr) * (que[t - 1].to - que[t - 1].fr)))
		{
			--t;
			if (onleft(que[t], line[i].fr)) que[t] = line[i];
		}
		if (h < t) inter[t - 1] = GetInt(que[t], que[t - 1]);
	}
	W (h < t && !onleft(que[h], inter[t - 1])) --t;
	if (t - h <= 1) return puts("0.0000"), 0;
	inter[t] = GetInt(que[t], que[h]);
	for (R int i = h + 2; i <= t; ++i) area += abs((inter[i - 1] - inter[h]) * (inter[i] - inter[h]) / 2);
	printf("%.4Lf", area / all);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章