QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#838495 | #5813. Lights | crimson231 | 66 ✓ | 8ms | 4260kb | C++23 | 13.6kb | 2024-12-31 12:26:43 | 2024-12-31 12:26:43 |
Judging History
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