洛谷傳送門
BZOJ傳送門
題目描述
小凸晚上喜歡到操場跑步,今天他跑完兩圈之後,他玩起了這樣一個遊戲。
操場是個凸 邊形, 個頂點按照逆時針從 編號。現在小凸隨機站在操場中的某個位置,標記爲 點。將 點與 個頂點各連一條邊,形成 個三角形。如果這時 點, 號點, 號點形成的三角形的面 積是 個三角形中最小的一個,小凸則認爲這是一次正確站位。
現在小凸想知道他一次站位正確的概率是多少。
輸入輸出格式
輸入格式:
第 行包含 個整數 , 表示操場的頂點數和遊戲的次數。
接下來有 行,每行包含 個整數 ,表示頂點的座標。
輸入保證按逆時針順序輸入點,所有點保證構成一個凸多邊形。所有點保證不存在三點共線。
輸出格式:
輸出 個數,正確站位的概率,保留 位小數。
輸入輸出樣例
輸入樣例#1:
5
1 8
0 7
0 0
8 0
8 8
輸出樣例#1:
0.6316
說明
對於 的數據,
對於 的數據,
解題分析
設一條邊兩端的兩個點爲, 那麼面積爲
再加上這個限制, 可得:
然後每個不等式都是一個半平面的形式, 搞搞半平面交就好了。
代碼如下:
#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);
}