Problem:
Problem J: Yu-kun Likes To Play Darts
Background
会津大学付属幼稚園はプログラミングが大好きな子供が集まる幼稚園である。園児の一人であるゆう君は、プログラミングと同じくらいダーツが大好きだ。
そんなゆう君は最近ダーツにはまっていたが、普通のダーツに飽きてしまったため独自のダーツボードを作ることにした。
ダーツについては
ダーツ
を参照。
Problem
ゆう君が考えたダーツの内容は以下の通りだ。
無限に広いダーツボードには得点の書かれた多角形が幾つかある。
プレイヤーはダーツの矢を1本だけ持っている。
プレイヤーは矢を投げ、いずれかの多角形に矢を刺すことでそこに書かれている得点を得る。
それ以外に刺さった場合は得点は得られない。
ゆう君は矢を投げる位置を決めたのだが、正確に刺さるとは限らない。
ダーツボードを2次元平面とし、ゆう君が狙う位置を点(
cx
,
cy
)とする。
ゆう君の投げた矢が刺さる場所は、点(
cx
,
cy
)を中心とする半径
r
の円に含まれる任意の点から一様な確率で選ばれる。
ばれる点の座標は整数である必要はない。
ダーツボードの情報とゆう君が狙う位置(
cx
,
cy
)、半径
r
が与えれるので、ゆう君が獲得することの出来る得点の期待値を答えよ。
Input
n
cx
cy
r
0番目の多角形の情報
1番目の多角形の情報
...
(n-1)
番目の多角形の情報
n
はダーツボード上にある多角形の数である。
多角形の情報は以下の形式で与えられる。
p
score
x
0
y
0
x
1
y
1
...
x
(p-1)
y
(p-1)
p
は多角形の頂点数を表し、
score
は多角形に書かれている得点を表す。
多角形の各線分は(
x
i
,
y
i
)と(
x
i+1
,
y
i+1
) (
i
<
p
-1 )の頂点を繋いだ線分と、(
x
p-1
,
y
p-1
)と(
x
0
,
y
0
)の頂点を繋いだ線分である。
Constraints
入力は以下の条件を満たす。
入力は全て整数で与えられる
1 ≤
n
≤ 50
0 ≤
cx
,
cy
,
x
,
y
≤ 1000
1 ≤
r
≤ 100
3 ≤
p
≤ 10
1 ≤
score
≤ 100
多角形の頂点は、隣り合った頂点を時計回り、または反時計回りに訪問するような順番で与えられる
多角形の辺が別の多角形の辺と共通な点をもつことはない
多角形が別の多角形を内包することはない
矢が多角形の辺上に刺さった場合、得点は得られないものとする
Output
ゆう君が獲得することの出来る得点の期待値を1行で出力せよ。小数点以下は何桁数字を出力しても構わない。ただし、解答の誤差は0.000001(10
-6
)を超えてはならない。
Sample Input 1
1 2 2 1
4 1
0 0
2 0
2 2
0 2
Sample Output 1
0.2500000000
Sample Input 2
1 2 2 1
4 1
0 0
5 0
5 5
0 5
Sample Output 2
1.0000000000
Sample Input 3
4 3 3 2
3 1
1 1
3 3
1 5
4 2
2 0
5 0
4 2
3 2
3 3
4 3
6 1
6 5
4 4
3 4
4 4
5 6
2 6
Sample Output 3
1.0574955319
Sample Input 4
1 10 10 1
4 10
0 0
1 0
1 1
0 1
Sample Output 4
0.0000000000

Submitted solutions:

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

// ==================================================================== Geometry Library ====================================================================
struct Point {
	long double px, py;
};

struct Circle {
	Point c;
	long double r;
};

Point operator+(const Point& a1, const Point& a2) {
	return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point& a1, const Point& a2) {
	return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point& a1, const long double& a2) {
	return Point{ a1.px * a2, a1.py * a2 };
}

bool operator<(const Point& a1, const Point& a2) {
	if (a1.px < a2.px) return true;
	return false;
}

// ノルム
long double norm(Point p) {
	return p.px * p.px + p.py * p.py;
}

// 距離
long double dist(Point p) {
	return sqrt(norm(p));
}

// 内積
long double dot(Point p1, Point p2) {
	return p1.px * p2.px + p1.py * p2.py;
}

// 外積
long double crs(Point p1, Point p2) {
	return p1.px * p2.py - p1.py * p2.px;
}

// 角度
long double angle(Point p) {
	return atan2(p.py, p.px);
}

// 射影
Point projection(Point p1, Point p2, Point x) {
	long double wari = dot(p2 - p1, x - p1) / norm(p1 - p2);
	return p1 + (p2 - p1) * wari;
}

// 線分と点の距離
long double dist_line(Point p1, Point p2, Point x) {
	long double val = abs(crs(p2 - p1, x - p1));
	return val / dist(p1 - p2);
}

// 線分と円の交点
vector<Point> cross_point(Point p1, Point p2, Circle c) {
	long double DST = dist_line(p1, p2, c.c);
	if (DST >= c.r - 1.0e-9L) return vector<Point>{};
	Point proj = projection(p1, p2, c.c);
	long double base = angle(proj - c.c); if (DST == 0) base = angle(p2 - p1) + 3.14159265358979L / 2.0L;
	long double diff = acos(DST / c.r);
	Point v1 = c.c + Point{ c.r * cos(base + diff), c.r * sin(base + diff) };
	Point v2 = c.c + Point{ c.r * cos(base - diff), c.r * sin(base - diff) };
	vector<Point> List;
	if (dist(p1 - v1) <= dist(p1 - p2) + 1.0e-9L && dist(p2 - v1) <= dist(p1 - p2) + 1.0e-9L) List.push_back(v1);
	if (dist(p1 - v2) <= dist(p1 - p2) + 1.0e-9L && dist(p2 - v2) <= dist(p1 - p2) + 1.0e-9L) List.push_back(v2);
	return List;
}

// 多角形の中に点が含まれるかを判定
bool isinside(vector<Point> Poly, Point P) {
	int cnt = 0;
	for (int i = 0; i < Poly.size(); i++) {
		Point v1 = Poly[(i + 0) % Poly.size()];
		Point v2 = Poly[(i + 1) % Poly.size()];
		if (v1.py > v2.py) swap(v1, v2);
		if (!(v1.py < P.py && P.py < v2.py)) continue;
		long double expected = v1.px + (v2.px - v1.px) * (P.py - v1.py) / (v2.py - v1.py);
		if (expected >= P.px) cnt += 1;
	}
	if (cnt % 2 == 1) return true;
	return false;
}

// 面積を計算
long double Area(vector<Point> Poly) {
	long double r = 0;
	for (int i = 0; i < Poly.size(); i++) {
		Point v1 = Poly[(i + 0) % Poly.size()];
		Point v2 = Poly[(i + 1) % Poly.size()];
		r += (v1.px + v2.px) * (v1.py - v2.py);
	}
	return abs(r) / 2.0;
}

// 多角形と円が交わる面積
long double GetArea(vector<Point> Poly, Circle C) {
	const int BUNKAI = 200000;
	int N = Poly.size();
	vector<vector<Point>> Cross(Poly.size(), vector<Point>{});
	vector<Point> Takakkei;

	// Step A. 交点の列挙
	for (int i = 0; i < N; i++) { if (dist(C.c - Poly[(i + 0) % N]) <= C.r) Cross[i].push_back(Poly[(i + 0) % N]); }
	for (int i = 0; i < N; i++) {
		Point v1 = Poly[(i + 0) % N];
		Point v2 = Poly[(i + 1) % N];
		vector<Point> ret = cross_point(v1, v2, C);
		vector<pair<double, Point>> List;
		for (Point j : ret) List.push_back(make_pair(dist(v1 - j), j));
		sort(List.begin(), List.end());
		for (int j = 0; j < List.size(); j++) Cross[i].push_back(List[j].second);
	}
	for (int i = 0; i < N; i++) { if (dist(C.c - Poly[(i + 1) % N]) <= C.r) Cross[i].push_back(Poly[(i + 1) % N]); }

	// Step B. 例外ケースの判定
	bool Flag = false;
	for (int i = 0; i < N; i++) {
		if (Cross[i].size() >= 1) Flag = true;
	}
	if (Flag == false) {
		Point base = C.c + Point{ C.r * cos(1.0), C.r * sin(1.0) };
		if (isinside(Poly, base) == true) return C.r * C.r * 3.14159265358979L;
		return 0.0;
	}

	// Step C. 最後の交点の角度を求める
	long double PrevAngle = 0;
	int PrevPlace = 0;
	for (int i = N - 1; i >= 0; i--) {
		if (Cross[i].size() == 0) continue;
		Point tmp = Cross[i][Cross[i].size() - 1];
		PrevAngle = angle(tmp - C.c);
		PrevPlace = i + 1;
		break;
	}

	// Step D. 多角形の近似を求める
	for (int i = 0; i < N; i++) {
		if (Cross[i].size() >= 1 && dist(C.c - Poly[i]) > C.r) {
			int cl = PrevPlace, cr = i; if (cl > cr) cr += N;
			long double AngleS = PrevAngle;
			long double AngleT = angle(Cross[i][0] - C.c);
			vector<Point> Vec;
			Vec.push_back(C.c + Point{ C.r * cos(PrevAngle), C.r * sin(PrevAngle) });
			for (int j = cl; j <= cr; j++) Vec.push_back(Poly[j % N]);
			Vec.push_back(Cross[i][0]);

			// 角度の合計を計算
			long double kakudosum = 0;
			for (int j = 0; j < Vec.size() - 1; j++) {
				double A1 = angle(Vec[j + 0] - C.c);
				double A2 = angle(Vec[j + 1] - C.c);
				while (A2 - A1 >= +3.14159265358979L) A2 -= 2.0L * 3.14159265358979L;
				while (A2 - A1 <= -3.14159265358979L) A2 += 2.0L * 3.14159265358979L;
				kakudosum += (A2 - A1);
			}
			if (kakudosum > 0.0 && AngleS > AngleT) AngleT += 2.0L * 3.14159265358979L;
			if (kakudosum < 0.0 && AngleS < AngleT) AngleT -= 2.0L * 3.14159265358979L;
			while (min(AngleS, AngleT) < 0.0) { AngleS += 2.0L * 3.14159265358979L; AngleT += 2.0L * 3.14159265358979L; }
			int c1 = 1.0 * BUNKAI * AngleS / (2.0L * 3.14159265358979L);
			int c2 = 1.0 * BUNKAI * AngleT / (2.0L * 3.14159265358979L);

			// 多角形の追加
			if (c1 <= c2) {
				for (int j = c1; j <= c2; j++) {
					long double px = C.c.px + C.r * cos(2.0L * 3.14159265358979L * j / BUNKAI);
					long double py = C.c.py + C.r * sin(2.0L * 3.14159265358979L * j / BUNKAI);
					Takakkei.push_back(Point{ px, py });
				}
			}
			else {
				for (int j = c1; j >= c2; j--) {
					long double px = C.c.px + C.r * cos(2.0L * 3.14159265358979L * j / BUNKAI);
					long double py = C.c.py + C.r * sin(2.0L * 3.14159265358979L * j / BUNKAI);
					Takakkei.push_back(Point{ px, py });
				}
			}
		}

		// 一般の場合
		for (Point j : Cross[i]) {
			Takakkei.push_back(j);
			PrevAngle = angle(j - C.c);
			PrevPlace = i + 1;
		}
	}

	// 面積を返す
	long double Return = Area(Takakkei);
	return Return;
}

// ==================================================================== Main Part ====================================================================
int N, Score[59];
int tmp;
Circle Target;
vector<Point> Dart[59];

int main() {
	// Step 1. Input
	cin >> N >> Target.c.px >> Target.c.py >> Target.r;
	for (int i = 0; i < N; i++) {
		cin >> tmp >> Score[i];
		Dart[i] = vector<Point>(tmp, Point{ 0.0L, 0.0L });
		for (int j = 0; j < tmp; j++) cin >> Dart[i][j].px >> Dart[i][j].py;
	}

	// Step 2. Find Answer
	long double TotalScore = 0.0;
	for (int i = 0; i < N; i++) {
		long double score1 = GetArea(Dart[i], Target);
		long double score2 = Score[i];
		TotalScore += score1 * score2;
	}

	// Step 3. Output
	long double Area_Circle = Target.r * Target.r * 3.14159265358979L;
	printf("%.12Lf\n", TotalScore / Area_Circle);
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 10480
final_rank: 1

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

// ==================================================================== Geometry Library ====================================================================
struct Point {
	long double px, py;
};

struct Circle {
	Point c;
	long double r;
};

Point operator+(const Point& a1, const Point& a2) {
	return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point& a1, const Point& a2) {
	return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point& a1, const long double& a2) {
	return Point{ a1.px * a2, a1.py * a2 };
}

bool operator<(const Point& a1, const Point& a2) {
	if (a1.px < a2.px) return true;
	return false;
}

// ノルム
long double norm(Point p) {
	return p.px * p.px + p.py * p.py;
}

// 距離
long double dist(Point p) {
	return sqrt(norm(p));
}

// 内積
long double dot(Point p1, Point p2) {
	return p1.px * p2.px + p1.py * p2.py;
}

// 外積
long double crs(Point p1, Point p2) {
	return p1.px * p2.py - p1.py * p2.px;
}

// 角度
long double angle(Point p) {
	return atan2(p.py, p.px);
}

// 射影
Point projection(Point p1, Point p2, Point x) {
	long double wari = dot(p2 - p1, x - p1) / norm(p1 - p2);
	return p1 + (p2 - p1) * wari;
}

// 線分と点の距離
long double dist_line(Point p1, Point p2, Point x) {
	long double val = abs(crs(p2 - p1, x - p1));
	return val / dist(p1 - p2);
}

// 線分と円の交点
vector<Point> cross_point(Point p1, Point p2, Circle c) {
	long double DST = dist_line(p1, p2, c.c);
	if (DST >= c.r - 1.0e-9L) return vector<Point>{};
	Point proj = projection(p1, p2, c.c);
	long double base = angle(proj - c.c); if (DST == 0) base = angle(p2 - p1) + 3.14159265358979L / 2.0L;
	long double diff = acos(DST / c.r);
	Point v1 = c.c + Point{ c.r * cos(base + diff), c.r * sin(base + diff) };
	Point v2 = c.c + Point{ c.r * cos(base - diff), c.r * sin(base - diff) };
	vector<Point> List;
	if (dist(p1 - v1) <= dist(p1 - p2) + 1.0e-9L && dist(p2 - v1) <= dist(p1 - p2) + 1.0e-9L) List.push_back(v1);
	if (dist(p1 - v2) <= dist(p1 - p2) + 1.0e-9L && dist(p2 - v2) <= dist(p1 - p2) + 1.0e-9L) List.push_back(v2);
	return List;
}

// 多角形の中に点が含まれるかを判定
bool isinside(vector<Point> Poly, Point P) {
	int cnt = 0;
	for (int i = 0; i < Poly.size(); i++) {
		Point v1 = Poly[(i + 0) % Poly.size()];
		Point v2 = Poly[(i + 1) % Poly.size()];
		if (v1.py > v2.py) swap(v1, v2);
		if (!(v1.py < P.py && P.py < v2.py)) continue;
		long double expected = v1.px + (v2.px - v1.px) * (P.py - v1.py) / (v2.py - v1.py);
		if (expected >= P.px) cnt += 1;
	}
	if (cnt % 2 == 1) return true;
	return false;
}

// 面積を計算
long double Area(vector<Point> Poly) {
	long double r = 0;
	for (int i = 0; i < Poly.size(); i++) {
		Point v1 = Poly[(i + 0) % Poly.size()];
		Point v2 = Poly[(i + 1) % Poly.size()];
		r += (v1.px + v2.px) * (v1.py - v2.py);
	}
	return abs(r) / 2.0;
}

// 多角形と円が交わる面積
long double GetArea(vector<Point> Poly, Circle C) {
	const int BUNKAI = 200000;
	int N = Poly.size();
	vector<vector<Point>> Cross(Poly.size(), vector<Point>{});
	vector<Point> Takakkei;

	// Step A. 交点の列挙
	for (int i = 0; i < N; i++) { if (dist(C.c - Poly[(i + 0) % N]) <= C.r) Cross[i].push_back(Poly[(i + 0) % N]); }
	for (int i = 0; i < N; i++) {
		Point v1 = Poly[(i + 0) % N];
		Point v2 = Poly[(i + 1) % N];
		vector<Point> ret = cross_point(v1, v2, C);
		vector<pair<double, Point>> List;
		for (Point j : ret) List.push_back(make_pair(dist(v1 - j), j));
		sort(List.begin(), List.end());
		for (int j = 0; j < List.size(); j++) Cross[i].push_back(List[j].second);
	}
	for (int i = 0; i < N; i++) { if (dist(C.c - Poly[(i + 1) % N]) <= C.r) Cross[i].push_back(Poly[(i + 1) % N]); }

	// Step B. 例外ケースの判定
	bool Flag = false;
	for (int i = 0; i < N; i++) {
		if (Cross[i].size() >= 1) Flag = true;
	}
	if (Flag == false) {
		Point base = C.c + Point{ C.r * cos(1.0), C.r * sin(1.0) };
		if (isinside(Poly, base) == true) return C.r * C.r * 3.14159265358979L;
		return 0.0;
	}

	// Step C. 最後の交点の角度を求める
	long double PrevAngle = 0;
	int PrevPlace = 0;
	for (int i = N - 1; i >= 0; i--) {
		if (Cross[i].size() == 0) continue;
		Point tmp = Cross[i][Cross[i].size() - 1];
		PrevAngle = angle(tmp - C.c);
		PrevPlace = i + 1;
		break;
	}

	// Step D. 多角形の近似を求める
	for (int i = 0; i < N; i++) {
		if (Cross[i].size() >= 1 && dist(C.c - Poly[i]) > C.r) {
			int cl = PrevPlace, cr = i; if (cl > cr) cr += N;
			long double AngleS = PrevAngle;
			long double AngleT = angle(Cross[i][0] - C.c);
			long double kakudosum = 0;
			for (int j = cl; j < cr; j++) {
				double A1 = angle(Poly[(j + 0) % N] - C.c);
				double A2 = angle(Poly[(j + 1) % N] - C.c);
				while (A2 - A1 >= +3.14159265358979L) A2 -= 2.0L * 3.14159265358979L;
				while (A2 - A1 <= -3.14159265358979L) A2 += 2.0L * 3.14159265358979L;
				kakudosum += (A2 - A1);
			}
			if (kakudosum > 0.0 && AngleS > AngleT) AngleT += 2.0L * 3.14159265358979L;
			if (kakudosum < 0.0 && AngleS < AngleT) AngleT -= 2.0L * 3.14159265358979L;
			while (min(AngleS, AngleT) < 0.0) { AngleS += 2.0L * 3.14159265358979L; AngleT += 2.0L * 3.14159265358979L; }
			int c1 = 1.0 * BUNKAI * AngleS / (2.0L * 3.14159265358979L);
			int c2 = 1.0 * BUNKAI * AngleT / (2.0L * 3.14159265358979L);

			// 多角形の追加
			if (c1 <= c2) {
				for (int j = c1; j <= c2; j++) {
					long double px = C.c.px + C.r * cos(2.0L * 3.14159265358979L * j / BUNKAI);
					long double py = C.c.py + C.r * sin(2.0L * 3.14159265358979L * j / BUNKAI);
					Takakkei.push_back(Point{ px, py });
				}
			}
			else {
				for (int j = c1; j >= c2; j--) {
					long double px = C.c.px + C.r * cos(2.0L * 3.14159265358979L * j / BUNKAI);
					long double py = C.c.py + C.r * sin(2.0L * 3.14159265358979L * j / BUNKAI);
					Takakkei.push_back(Point{ px, py });
				}
			}
		}

		// 一般の場合
		for (Point j : Cross[i]) {
			Takakkei.push_back(j);
			PrevAngle = angle(j - C.c);
			PrevPlace = i + 1;
		}
	}

	// 面積を返す
	long double Return = Area(Takakkei);
	return Return;
}

// ==================================================================== Main Part ====================================================================
int N, Score[59];
int tmp;
Circle Target;
vector<Point> Dart[59];

int main() {
	// Step 1. Input
	cin >> N >> Target.c.px >> Target.c.py >> Target.r;
	for (int i = 0; i < N; i++) {
		cin >> tmp >> Score[i];
		Dart[i] = vector<Point>(tmp, Point{ 0.0L, 0.0L });
		for (int j = 0; j < tmp; j++) cin >> Dart[i][j].px >> Dart[i][j].py;
	}

	// Step 2. Find Answer
	long double TotalScore = 0.0;
	for (int i = 0; i < N; i++) {
		long double score1 = GetArea(Dart[i], Target);
		long double score2 = Score[i];
		TotalScore += score1 * score2;
	}

	// Step 3. Output
	long double Area_Circle = Target.r * Target.r * 3.14159265358979L;
	printf("%.12Lf\n", TotalScore / Area_Circle);
	return 0;
}
accuracy: 0.6153846153846154
time_ms: 30
memory_kb: 17712
final_rank: 2

code_snippet: #include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

// ==================================================================== Geometry Library ====================================================================
struct Point {
	long double px, py;
};

struct Circle {
	Point c;
	long double r;
};

Point operator+(const Point& a1, const Point& a2) {
	return Point{ a1.px + a2.px, a1.py + a2.py };
}

Point operator-(const Point& a1, const Point& a2) {
	return Point{ a1.px - a2.px, a1.py - a2.py };
}

Point operator*(const Point& a1, const long double& a2) {
	return Point{ a1.px * a2, a1.py * a2 };
}

bool operator<(const Point& a1, const Point& a2) {
	if (a1.px < a2.px) return true;
	return false;
}

// ノルム
long double norm(Point p) {
	return p.px * p.px + p.py * p.py;
}

// 距離
long double dist(Point p) {
	return sqrt(norm(p));
}

// 内積
long double dot(Point p1, Point p2) {
	return p1.px * p2.px + p1.py * p2.py;
}

// 外積
long double crs(Point p1, Point p2) {
	return p1.px * p2.py - p1.py * p2.px;
}

// 角度
long double angle(Point p) {
	return atan2(p.py, p.px);
}

// 射影
Point projection(Point p1, Point p2, Point x) {
	long double wari = dot(p2 - p1, x - p1) / norm(p1 - p2);
	return p1 + (p2 - p1) * wari;
}

// 線分と点の距離
long double dist_line(Point p1, Point p2, Point x) {
	long double val = abs(crs(p2 - p1, x - p1));
	return val / dist(p1 - p2);
}

// 線分と円の交点
vector<Point> cross_point(Point p1, Point p2, Circle c) {
	long double DST = dist_line(p1, p2, c.c);
	if (DST >= c.r - 1.0e-9L) return vector<Point>{};
	Point proj = projection(p1, p2, c.c);
	long double base = angle(proj - c.c); if (DST == 0) base = angle(p2 - p1) + 3.14159265358979L / 2.0L;
	long double diff = acos(DST / c.r);
	Point v1 = c.c + Point{ c.r * cos(base + diff), c.r * sin(base + diff) };
	Point v2 = c.c + Point{ c.r * cos(base - diff), c.r * sin(base - diff) };
	vector<Point> List;
	if (dist(p1 - v1) <= dist(p1 - p2) + 1.0e-9L && dist(p2 - v1) <= dist(p1 - p2) + 1.0e-9L) List.push_back(v1);
	if (dist(p1 - v2) <= dist(p1 - p2) + 1.0e-9L && dist(p2 - v2) <= dist(p1 - p2) + 1.0e-9L) List.push_back(v2);
	return List;
}

// 多角形の中に点が含まれるかを判定
bool isinside(vector<Point> Poly, Point P) {
	int cnt = 0;
	for (int i = 0; i < Poly.size(); i++) {
		Point v1 = Poly[(i + 0) % Poly.size()];
		Point v2 = Poly[(i + 1) % Poly.size()];
		if (v1.py > v2.py) swap(v1, v2);
		if (!(v1.py < P.py && P.py < v2.py)) continue;
		long double expected = v1.px + (v2.px - v1.px) * (P.py - v1.py) / (v2.py - v1.py);
		if (expected >= P.px) cnt += 1;
	}
	if (cnt % 2 == 1) return true;
	return false;
}

// 面積を計算
long double Area(vector<Point> Poly) {
	long double r = 0;
	for (int i = 0; i < Poly.size(); i++) {
		Point v1 = Poly[(i + 0) % Poly.size()];
		Point v2 = Poly[(i + 1) % Poly.size()];
		r += (v1.px + v2.px) * (v1.py - v2.py);
	}
	return abs(r) / 2.0;
}

// 多角形と円が交わる面積
long double GetArea(vector<Point> Poly, Circle C) {
	const int BUNKAI = 200000;
	int N = Poly.size();
	vector<vector<Point>> Cross(Poly.size(), vector<Point>{});
	vector<Point> Takakkei;

	// Step A. 交点の列挙
	for (int i = 0; i < N; i++) { if (dist(C.c - Poly[(i + 0) % N]) <= C.r) Cross[i].push_back(Poly[(i + 0) % N]); }
	for (int i = 0; i < N; i++) {
		Point v1 = Poly[(i + 0) % N];
		Point v2 = Poly[(i + 1) % N];
		vector<Point> ret = cross_point(v1, v2, C);
		vector<pair<double, Point>> List;
		for (Point j : ret) List.push_back(make_pair(dist(v1 - j), j));
		sort(List.begin(), List.end());
		for (int j = 0; j < List.size(); j++) Cross[i].push_back(List[j].second);
	}
	for (int i = 0; i < N; i++) { if (dist(C.c - Poly[(i + 1) % N]) <= C.r) Cross[i].push_back(Poly[(i + 1) % N]); }

	// Step B. 例外ケースの判定
	bool Flag = false;
	for (int i = 0; i < N; i++) {
		if (Cross[i].size() >= 1) Flag = true;
	}
	if (Flag == false) {
		Point base = C.c + Point{ C.r * cos(1.0), C.r * sin(1.0) };
		if (isinside(Poly, base) == true) return C.r * C.r * 3.14159265358979L;
		return 0.0;
	}

	// Step C. 最後の交点の角度を求める
	double PrevAngle = 0;
	int PrevPlace = 0;
	for (int i = N - 1; i >= 0; i--) {
		if (Cross[i].size() == 0) continue;
		Point tmp = Cross[i][Cross[i].size() - 1];
		PrevAngle = angle(tmp - C.c);
		PrevPlace = i + 1;
		break;
	}

	// Step D. 多角形の近似を求める
	for (int i = 0; i < N; i++) {
		if (Cross[i].size() >= 1 && dist(C.c - Poly[i]) > C.r) {
			int cl = PrevPlace, cr = i; if (cl > cr) cr += N;
			long double AngleS = PrevAngle;
			long double AngleT = angle(Cross[i][0] - C.c);
			long double kakudosum = 0;
			for (int j = cl; j < cr; j++) {
				double A1 = angle(Poly[(j + 0) % N] - C.c);
				double A2 = angle(Poly[(j + 1) % N] - C.c);
				while (A2 - A1 >= +3.14159265358979L) A2 -= 2.0L * 3.14159265358979L;
				while (A2 - A1 <= -3.14159265358979L) A2 += 2.0L * 3.14159265358979L;
				kakudosum += (A2 - A1);
			}
			if (kakudosum > 0.0 && AngleS > AngleT) AngleT += 2.0L * 3.14159265358979L;
			if (kakudosum < 0.0 && AngleS < AngleT) AngleT -= 2.0L * 3.14159265358979L;
			while (min(AngleS, AngleT) < 0.0) { AngleS += 2.0L * 3.14159265358979L; AngleT += 2.0L * 3.14159265358979L; }
			int c1 = 1.0 * BUNKAI * AngleS / (2.0 * 3.14159265358979);
			int c2 = 1.0 * BUNKAI * AngleT / (2.0 * 3.14159265358979);

			// 多角形の追加
			if (c1 <= c2) {
				for (int j = c1; j <= c2; j++) {
					long double px = C.c.px + C.r * cos(2.0L * 3.14159265358979L * j / BUNKAI);
					long double py = C.c.py + C.r * sin(2.0L * 3.14159265358979L * j / BUNKAI);
					Takakkei.push_back(Point{ px, py });
				}
			}
			else {
				for (int j = c2; j >= c1; j--) {
					long double px = C.c.px + C.r * cos(2.0L * 3.14159265358979L * j / BUNKAI);
					long double py = C.c.py + C.r * sin(2.0L * 3.14159265358979L * j / BUNKAI);
					Takakkei.push_back(Point{ px, py });
				}
			}
		}

		// 一般の場合
		for (Point j : Cross[i]) {
			Takakkei.push_back(j);
			PrevAngle = angle(j - C.c);
			PrevPlace = i + 1;
		}
	}

	// 面積を返す
	long double Return = Area(Takakkei);
	return Return;
}

// ==================================================================== Main Part ====================================================================
int N, Score[59];
int tmp;
Circle Target;
vector<Point> Dart[59];

int main() {
	// Step 1. Input
	cin >> N >> Target.c.px >> Target.c.py >> Target.r;
	for (int i = 0; i < N; i++) {
		cin >> tmp >> Score[i];
		Dart[i] = vector<Point>(tmp, Point{ 0.0L, 0.0L });
		for (int j = 0; j < tmp; j++) cin >> Dart[i][j].px >> Dart[i][j].py;
	}

	// Step 2. Find Answer
	long double TotalScore = 0.0;
	for (int i = 0; i < N; i++) {
		long double score1 = GetArea(Dart[i], Target);
		long double score2 = Score[i];
		TotalScore += score1 * score2;
	}

	// Step 3. Output
	long double Area_Circle = Target.r * Target.r * 3.14159265358979L;
	printf("%.12Lf\n", TotalScore / Area_Circle);
	return 0;
}
accuracy: 0.38461538461538464
time_ms: 20
memory_kb: 10056
final_rank: 3