QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#838495#5813. Lightscrimson23166 ✓8ms4260kbC++2313.6kb2024-12-31 12:26:432024-12-31 12:26:43

Judging History

你现在查看的是最新测评结果

  • [2024-12-31 12:26:43]
  • 评测
  • 测评结果:66
  • 用时:8ms
  • 内存:4260kb
  • [2024-12-31 12:26:43]
  • 提交

answer

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <random>
#include <cassert>
#include <array>
#include <tuple>
#include <deque>
#include <iomanip>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::pair<int, int> pi;
typedef std::vector<size_t> Vidx;
typedef std::vector<int> Vint;
typedef std::vector<ld> Vld;
typedef std::vector<bool> Vbool;
const ld INF = 1e17;
const ld TOL = 1e-10;
const int LEN = 55;
const ld PI = acos(-1);
inline int sign(const ll& x) { return x < 0 ? -1 : !!x; }
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }
inline ld sq(const ld& x) { return x * x; }
inline ll sq(const ll& x) { return x * x; }
inline ld norm(ld th) { while (th < 0) th += 2 * PI; while (sign(th - 2 * PI) >= 0) th -= 2 * PI; return th; }
inline ld fit(const ld& x, const ld& lo, const ld& hi) { return std::min(hi, std::max(lo, x)); }
#define LINE 1
#define CIRCLE 2
#define STRONG 0
#define WEAK 1
#define LO x
#define HI y
#define BLACK 0
#define RED 1
#define GREEN 2
#define YELLOW 3

int N, M, T, Q;
ld A[4];
struct Pos {
	ld x, y;
	Pos(ld X_ = 0, ld y_ = 0) : x(X_), y(y_) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& n) const { return { x * n, y * n }; }
	Pos operator / (const ld& n) const { return { x / n, y / n }; }
	ld operator * (const Pos& p) const { return { x * p.x + y * p.y }; }
	ld operator / (const Pos& p) const { return { x * p.y - y * p.x }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { -x, -y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos rot(const ld& t) { return { x * cos(t) - y * sin(t), x * sin(t) + y * cos(t) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << p.x << " " << p.y; return os; }
} P[4]; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) * (d4 - d3); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
bool inside(const Pos& p0, const Pos& p1, const Pos& p2, const Pos& q, const int& f = STRONG) {
	if (ccw(p0, p1, p2) < 0) return ccw(p0, p1, q) >= f || ccw(p1, p2, q) >= f;
	return ccw(p0, p1, q) >= f && ccw(p1, p2, q) >= f;
}
bool intersect(const Pos& s1, const Pos& s2, const Pos& d1, const Pos& d2) {
	bool f1 = ccw(s1, s2, d1) * ccw(s2, s1, d2) > 0;
	bool f2 = ccw(d1, d2, s1) * ccw(d2, d1, s2) > 0;
	bool f3 = on_seg_strong(s1, s2, d1) ||
		on_seg_strong(s1, s2, d2) ||
		on_seg_strong(d1, d2, s1) ||
		on_seg_strong(d1, d2, s2);
	return (f1 && f2) || f3;
}
ld area(const Polygon& H) {
	int sz = H.size();
	ld a = 0;
	for (int i = 0; i < sz; i++) a += H[i] / H[(i + 1) % sz];
	return a * .5;
}
Polygon convex_cut(const std::vector<Pos>& ps, const Pos& b1, const Pos& b2) {
	std::vector<Pos> qs;
	int n = ps.size();
	for (int i = 0; i < n; i++) {
		Pos p1 = ps[i], p2 = ps[(i + 1) % n];
		int d1 = ccw(b1, b2, p1), d2 = ccw(b1, b2, p2);
		if (d1 >= 0) qs.push_back(p1);
		if (d1 * d2 < 0) qs.push_back(intersection(p1, p2, b1, b2));
	}
	return qs;
}
Polygon sutherland_hodgman(const std::vector<Pos>& C, const std::vector<Pos>& clip) {
	int sz = clip.size();
	std::vector<Pos> ret = C;
	for (int i = 0; i < sz; i++) {
		Pos b1 = clip[i], b2 = clip[(i + 1) % sz];
		ret = convex_cut(ret, b1, b2);
	}
	return ret;
}
struct Seg {
	Pos s, e;
	Seg(Pos s_ = Pos(), Pos e_ = Pos()) : s(s_), e(e_) {}
	Pos p(const ld& rt) const { return s + (e - s) * rt; }
	ld green(const ld& lo = 0, const ld& hi = 1) const {
		ld d = hi - lo;
		ld ratio = (lo + hi) * .5;
		Pos m = p(ratio);
		return m.y * d * (s.x - e.x);
	}
};
Seg S[4][LEN];
typedef std::vector<Seg> Segs;
ld dot(const Seg& p, const Seg& q) { return dot(p.s, p.e, q.s, q.e); }
bool intersect(const Seg& u, const Seg& v) { return intersect(u.s, u.e, v.s, v.e); }
struct Circle {
	Pos c;
	int r;
	Circle(Pos c_ = Pos(), int r_ = 0) : c(c_), r(r_) {}
	bool operator == (const Circle& q) const { return c == q.c && r == q.r; }
	bool operator < (const Circle& q) const { return c == q.c ? r < q.r : c < q.c; }
	bool operator < (const Pos& p) const { return sign(r - (c - p).mag()) < 0; }
	bool operator <= (const Pos& p) const { return sign(r - (c - p).mag()) <= 0; }
	bool operator == (const Pos& p) const { return sign(r - (c - p).mag()) == 0; }
	bool operator > (const Pos& p) const { return sign(r - (c - p).mag()) > 0; }
	bool operator >= (const Pos& p) const { return sign(r - (c - p).mag()) >= 0; }
	bool outside(const Circle& q) const { return sign((c - q.c).Euc() - sq((ll)r + q.r)) >= 0; }
	Pos p(const ld& t) const { return c + Pos(r, 0).rot(t); }
	ld rad(const Pos& p) const { return norm((p - c).rad()); }
	ld area(const ld& lo = 0, const ld& hi = 2 * PI) const { return (hi - lo) * r * r * .5; }
	ld green(const ld& lo, const ld& hi) const {
		Pos s = Pos(cos(lo), sin(lo)), e = Pos(cos(hi), sin(hi));
		ld fan = area(lo, hi);
		Pos m = c + (s + e) * r * (ld).5;
		ld tz = (cos(lo) - cos(hi)) * m.y * r;
		return fan + tz - (s / e) * r * r * (ld).5;
	}
	inline friend std::istream& operator >> (std::istream& is, Circle& c) { is >> c.c >> c.r; return is; }
	inline friend std::ostream& operator << (std::ostream& os, const Circle& c) { os << c.c << " " << c.r; return os; }
};
typedef std::vector<Circle> Circles;
Circles C;
Vld circle_line_intersections(const Circle& q, const Seg& l, const int& t = LINE) {
	//https://math.stackexchange.com/questions/311921/get-location-of-vector-circle-intersection
	Pos s = l.s, e = l.e;
	Pos vec = e - s;
	Pos OM = s - q.c;
	ld a = vec.Euc();
	ld b = vec * OM;
	ld c = OM.Euc() - (ll)q.r * q.r;
	ld J = b * b - a * c;
	if (J < -TOL) return {};
	ld det = sqrt(std::max((ld)0, J));
	ld lo = (-b - det) / a;
	ld hi = (-b + det) / a;
	Vld ret;
	if (t == LINE) {
		//if (0 < lo && lo < 1) ret.push_back(lo);
		//if (zero(det)) return ret;
		//if (0 < hi && hi < 1) ret.push_back(hi);
		ret.push_back(lo);
		ret.push_back(hi);
	}
	else {//circle
		auto the = [&](ld rt) { return q.rad(s + (e - s) * rt); };
		if (-TOL < lo && lo < 1 + TOL) ret.push_back(the(lo));
		if (zero(det)) return ret;
		if (-TOL < hi && hi < 1 + TOL) ret.push_back(the(hi));
		//ret.push_back(the(lo));
		//ret.push_back(the(hi));
	}
	return ret;
}
ld intersection(const Seg& s1, const Seg& s2, const bool& f = STRONG) {
	const Pos& p1 = s1.s, p2 = s1.e, q1 = s2.s, q2 = s2.e;
	ld det = (q2 - q1) / (p2 - p1);
	if (zero(det)) return -1;
	ld a1 = ((q2 - q1) / (q1 - p1)) / det;
	ld a2 = ((p2 - p1) / (p1 - q1)) / -det;
	if (f == WEAK) return fit(a1, 0, 1);
	if (0 < a1 && a1 < 1 && -TOL < a2 && a2 < 1 + TOL) return a1;
	return -1;
}
Vld tangents(const Pos& p, const Circle& c, Polygon& vp, const bool& f = 0) {
	assert(c < p);
	Pos v = p - c.c;
	ld l = v.mag();
	ld h = c.r, w = sqrtl(l * l - h * h);
	ld t = v.rad(), r = atan2(w, h);
	ld lo = norm(t - r);
	ld hi = norm(t + r);
	if (f) vp.push_back(c.p(lo)), vp.push_back(c.p(hi));
	return { lo, hi };
}
bool inner_check(const Polygon& H, const Pos& q) {
	int sz = H.size();
	for (int i = 0; i < sz; i++) if (ccw(H[i], H[(i + 1) % sz], q) < 0) return 0;
	return 1;
}
Pos get_pos(const Pos& l, const Seg& p, const Seg& q) {
	Pos p1 = p.s, p2 = p.e, q1 = q.s, q2 = q.e;
	if (!inside(p2, l, p1, q1, WEAK) && !inside(p2, l, p1, q2, WEAK)) {
		if (intersect(l, p1, q1, q2) && intersect(l, p2, q1, q2)) return Pos(0, 1);
		else return Pos(0, 0);
	}
	Polygon tri = { p1, p2, l };
	bool in1 = inner_check(tri, q1), in2 = inner_check(tri, q2);
	if (!in1 && !in2) return Pos(0, 0);
	ld r1 = 0, r2 = 1;
	if (in1 && in2) {
		r1 = intersection(p, Seg(l, q1), WEAK);
		r2 = intersection(p, Seg(l, q2), WEAK);
	}
	else if (in1) r1 = intersection(p, Seg(l, q1), WEAK);
	else if (in2) r2 = intersection(p, Seg(l, q2), WEAK);
	else r1 = r2 = 0;
	if (r2 < r1) std::swap(r1, r2);
	return Pos(r1, r2);
}
ld circle_cut(const Circle& c, const Seg& s) {
	Pos v1 = s.s - c.c, v2 = s.e - c.c;
	ll r = c.r;
	Vld inx = circle_line_intersections(c, s, LINE);
	if (inx.empty()) return r * r * rad(v1, v2) * .5;
	Pos m1, m2;
	if (inx.size() == 2) m1 = s.p(inx[0]), m2 = s.p(inx[1]);
	else m1 = m2 = c.p(inx[0]);
	m1 -= c.c; m2 -= c.c;
	bool d1 = dot(m1, v1, m2) > -TOL, d2 = dot(m1, v2, m2) > -TOL;
	if (d1 && d2) return (v1 / v2) * .5;
	else if (d1) return (v1 / m2 + r * r * rad(m2, v2)) * .5;
	else if (d2) return (r * r * rad(v1, m1) + m1 / v2) * .5;
	else if (dot(v1, m1, v2) > 0 && dot(v1, m2, v2) > 0)
		return (r * r * (rad(v1, m1) + rad(m2, v2)) + m1 / m2) * .5;
	else return (r * r * rad(v1, v2)) * .5;
}
ld green(const Circle& c, const Polygon& h) {
	int sz = h.size();
	ld a = 0;
	for (int i = 0; i < sz; i++) a += circle_cut(c, Seg(h[i], h[(i + 1) % sz]));
	return a;
}
struct Frag {
	int t;
	Polygon p;
	Frag(int t_ = -1, Polygon p_ = {}) : t(t_), p(p_) {}
	ld a() const { return area(p) - (~t ? green(C[t], p) : 0); }
};
typedef std::vector<Frag> Frags;
Frags F[4];
ld intersection(const Frag& a, const Frag& b) {
	Polygon P = sutherland_hodgman(a.p, b.p);
	ld A = area(P);
	if (!P.size() || zero(A)) return 0;
	if (~a.t) A -= green(C[a.t], P);
	if (~b.t && b.t != a.t) A -= green(C[b.t], P);
	return A;
}
void query(const int& q) {
	memset(A, 0, sizeof A);
	for (int i = 0; i < 4; i++) F[i].clear();
	std::cin >> P[RED] >> P[GREEN] >> N;
	if (!N) { std::cout << "Case #" << q << ":\n0\n0\n0\n10000\n"; return; }
	C.resize(N); for (Circle& c : C) std::cin >> c;
	Polygon B = { Pos(0, 0), Pos(100, 0), Pos(100, 100), Pos(0, 100) };//boundary
	for (int i = 0; i < N; i++) {//preparing line sweeping
		for (int color = 1; color <= 2; color++) {
			Polygon vp;
			tangents(P[color], C[i], vp, 1);
			Pos s = vp[1], e = vp[0];
			S[color][i] = Seg(s, e);
		}
	}
	for (int t = 0; t < 4; t++) {//dividing the boundary
		Seg b = Seg(B[t], B[(t + 1) % 4]);
		for (int color = 1; color <= 2; color++) {
			Polygon VP = { Pos(0, 0) };
			for (int i = 0; i < N; i++) {
				Pos se = get_pos(P[color], b, S[color][i]);
				if (!eq(se.x, se.y)) VP.push_back(se);
			}
			VP.push_back(Pos(1, 1));
			std::sort(VP.begin(), VP.end());
			ld hi = 0;
			for (const Pos& p : VP) {
				if (hi < p.LO) {
					Pos s = b.p(hi);
					Pos e = b.p(p.LO);
					Polygon tri = { P[color], s, e };
					Frag fr = Frag(-1, tri);
					F[color].push_back(fr);
					hi = p.HI;
				}
				else hi = std::max(hi, p.HI);
			}
		}
	}
	for (int color = 1; color <= 2; color++) {//triangulation
		for (int i = 0; i < N; i++) {
			Polygon VP = { Pos(0, 0) };
			for (int j = 0; j < N; j++) {
				if (i == j) continue;
				Pos se = get_pos(P[color], S[color][i], S[color][j]);
				if (!eq(se.x, se.y)) VP.push_back(se);
			}
			VP.push_back(Pos(1, 1));
			std::sort(VP.begin(), VP.end());
			ld hi = 0;
			for (const Pos& p : VP) {
				if (hi < p.LO) {
					Pos s = S[color][i].p(hi);
					Pos e = S[color][i].p(p.LO);
					Polygon tri = { P[color], s, e };
					Frag fr = Frag(i, tri);
					F[color].push_back(fr);
					hi = p.HI;
				}
				else hi = std::max(hi, p.HI);
			}
		}
	}
	Frags& R = F[RED];
	Frags& G = F[GREEN];
	for (const Frag& r : R) A[RED] += r.a();
	for (const Frag& g : G) A[GREEN] += g.a();
	for (const Frag& r : R) {
		for (const Frag& g : G) {
			A[YELLOW] += intersection(r, g);
		}
	}
	A[RED] -= A[YELLOW];
	A[GREEN] -= A[YELLOW];
	A[BLACK] = 10000 - A[RED] - A[GREEN] - A[YELLOW];
	for (int i = 0; i < N; i++) A[BLACK] -= C[i].area();
	std::cout << "Case #" << q << ":\n";
	std::cout << A[BLACK] << "\n";
	std::cout << A[RED] << "\n";
	std::cout << A[GREEN] << "\n";
	std::cout << A[YELLOW] << "\n";
	return;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout << std::scientific;
	//std::cout.precision(15);
	std::cin >> T;
	for (int q = 1; q <= T; q++) query(q);
	return;
}
int main() { solve(); return 0; }//boj12620 lights

Details

Tip: Click on the bar to expand more detailed information

Subtask #1:

score: 21
Accepted

Test #1:

score: 21
Accepted
time: 1ms
memory: 4240kb

input:

15
62 82
32 93
0
93 16
14 21
1
51 50 47
20 20
99 99
1
2 2 1
78 38
1 95
1
35 38 14
1 1
99 99
1
50 50 49
3 1
1 1
1
2 2 1
19 95
98 61
1
46 36 18
1 1
1 2
1
50 50 49
1 99
99 98
1
50 50 49
34 26
64 78
1
69 28 24
20 1
20 98
1
20 50 1
85 93
34 3
1
85 61 11
5 50
95 50
1
50 50 10
93 16
14 21
1
51 50 47
15 90
...

output:

Case #1:
0
0
0
10000
Case #2:
1.756203e+03
6.988190e+02
6.052001e+02
0.000000e+00
Case #3:
3.110350e+00
2.000888e-11
1.049071e-01
9.993643e+03
Case #4:
4.268581e+01
1.384467e+03
1.110224e+03
6.846871e+03
Case #5:
1.030518e+03
7.122590e+02
7.122590e+02
2.000000e+00
Case #6:
1.944292e+02
9.603215e+03
...

result:

ok correct! (15 test cases)

Subtask #2:

score: 45
Accepted

Test #2:

score: 45
Accepted
time: 8ms
memory: 4260kb

input:

15
1 98
2 99
27
18 18 1
74 74 1
30 30 1
10 10 1
78 78 1
6 6 1
50 50 1
86 86 1
2 2 1
26 26 1
82 82 1
34 34 1
66 66 1
80 50 19
46 46 1
62 62 1
98 98 1
58 58 1
42 42 1
90 90 1
38 38 1
54 54 1
94 94 1
22 22 1
70 70 1
14 14 1
50 20 19
5 5
40 5
6
60 60 35
39 10 1
50 15 1
15 10 1
90 5 4
10 15 1
88 22
72 29...

output:

Case #1:
1.646991e+03
9.931063e+01
9.931063e+01
5.807618e+03
Case #2:
1.181276e+03
1.172647e+03
8.015251e+02
2.933269e+03
Case #3:
2.586127e+03
2.252150e+03
1.258290e+03
3.746353e+03
Case #4:
3.960207e+03
1.312161e+03
1.766736e+03
2.803817e+03
Case #5:
2.474676e+03
2.302890e+03
2.356447e+03
2.379041...

result:

ok correct! (15 test cases)

Extra Test:

score: 0
Extra Test Passed