#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cassert>
#include <vector>
#include <deque>
typedef long long ll;
//typedef double ld;
typedef long double ld;
const ld INF = 1e17;
const ld TOL = 1e-10;
const ld PI = acos(-1);
const int LEN = 25;
int N, M, T, Q;
bool zero(const ld& x) { return std::abs(x) < TOL; }
int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
ld norm(ld th) {
while (th < 0) th += PI * 2;
while (th > PI * 2 - TOL) th -= PI * 2;
return th;
}
//#define DEBUG
//#define ASSERT
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& scalar) const { return { x * scalar, y * scalar }; }
Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
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 Pos& p) const { return { x * p.x, y * p.y }; }
Pos operator - () const { return { -x, -y }; }
Pos operator ~ () const { return { -y, x }; }
Pos operator ! () const { return { y, x }; }
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; }
ld xy() const { return x * y; }
Pos rot(ld the) const { return Pos(x * cos(the) - y * sin(the), x * sin(the) + y * cos(the)); }
ld Euc() const { return x * x + y * y; }
ld mag() const { return sqrt(Euc()); }
//ld mag() const { return hypotl(x, y); }
Pos unit() const { return *this / mag(); }
ld rad() const { return norm(atan2(y, x)); }
friend ld rad(const Pos& p1, const Pos& p2) { return norm(atan2(p1 / p2, p1 * p2)); }
int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
bool close(const Pos& p) const { return zero((*this - p).Euc()); }
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; }
};
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) {
ld ret = cross(d1, d2, d3);
return zero(ret) ? 0 : ret > 0 ? 1 : -1;
}
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);
}
struct Circle {
Pos c;
int r;
Circle(Pos C = Pos(0, 0), int R = 0) : c(C), r(R) {}
bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
bool operator != (const Circle& C) const { return !(*this == C); }
bool operator < (const Circle& q) const {
ld dist = (c - q.c).mag();
return r < q.r && dist + r < q.r + TOL;
}
bool operator > (const Pos& p) const { return r > (c - p).mag(); }
bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
bool operator < (const Pos& p) const { return r < (c - p).mag(); }
Circle operator + (const Circle& C) const { return { c + C.c, r + C.r }; }
Circle operator - (const Circle& C) const { return { c - C.c, r - C.r }; }
ld H(const ld& th) const { return sin(th) * c.x + cos(th) * c.y + r; }//coord trans | check right
ld A() const { return 1. * r * r * PI; }
friend std::istream& operator >> (std::istream& is, Circle& c) { is >> c.c >> c.r; return is; }
friend std::ostream& operator << (std::ostream& os, const Circle& c) { os << c.c << " " << c.r; return os; }
};
typedef std::vector<Circle> Disks;
struct Arc {
ld lo, hi;// [lo, hi] - radian range of arc, 0 ~ 2pi
Circle cen;
Arc(ld LO = 0, ld HI = 0, Circle CEN = Circle(Pos(0, 0), 0)) : lo(LO), hi(HI), cen(CEN) {}
bool operator < (const Arc& a) const { return !sign(lo - a.lo) ? hi < a.hi : lo < a.lo; }
ld area() const { return norm(hi - lo) * cen.r * cen.r; }
ld green() const {
Pos LO = -Pos(1, 0).rot(lo);
Pos HI = Pos(1, 0).rot(hi);
return (area() + cen.c / (HI + LO) * cen.r) * .5;
}
friend std::ostream& operator << (std::ostream& os, const Arc& l) { os << l.lo << " " << l.hi << " " << l.cen.r; return os; }
};
typedef std::vector<Arc> Arcs;
std::vector<Pos> intersection(const Circle& a, const Circle& b) {
Pos ca = a.c, cb = b.c;
Pos vec = cb - ca;
ld ra = a.r, rb = b.r;
ld distance = vec.mag();
if (distance > ra + rb - TOL) return {};
if (distance < std::abs(ra - rb) + TOL) return {};
//2nd hyprblc law of cos
ld X = (ra * ra - rb * rb + vec.Euc()) / (2 * distance);
if (X < -ra + TOL || X > ra - TOL) return {};
ld ratio = sqrt(ra * ra - X * X);
Pos w = vec * X / distance;
Pos h = ~vec.unit() * ratio;
if (zero(ratio)) return { w };
return { w - h, w + h };
}
ld union_except_x(const int& x, std::vector<Circle>& VC) {
ld union_area = 0;
int sz = VC.size();
for (int i = 0; i < sz; i++) {
if (i == x) continue;
Circle& disk = VC[i];
Arcs arcs;
for (int j = 0; j < sz; j++) {
if (j == x || j == i) continue;
Pos& ca = VC[i].c, cb = VC[j].c;
auto inx = intersection(VC[i], VC[j]);
//std::cout << inx.size() << "\n";
if (inx.size() < 2) continue;
ld lo = inx[0].rad();
ld hi = inx[1].rad();
//ll ra = VC[i].r, rb = VC[j].r;
//Pos vec = cb - ca;//vec a -> b
//ld distance = vec.mag();
//ld X = (ra * ra - rb * rb + vec.Euc()) / (2 * distance);
//if (X < -ra + TOL || X > ra - TOL) continue;
//ld ratio = sqrt(ra * ra - X * X);
//Pos w = vec * X / distance;
//Pos h = ~vec.unit() * ratio;
//ld lo = (w - h).rad(), hi = (w + h).rad();
Arc a1, a2;
if (sign(hi - lo) >= 0) {
a1 = Arc(lo, hi, disk);
arcs.push_back(a1);
}
else {
a1 = Arc(lo, PI * 2, disk);
a2 = Arc(0, hi, disk);
arcs.push_back(a1);
arcs.push_back(a2);
}
}
if (!arcs.size()) {
//std::cout << "i : " << i << "\n";
union_area += disk.A();
continue;
}
std::sort(arcs.begin(), arcs.end());
arcs.push_back(Arc(2 * PI, 2 * PI, disk));
ld hi = 0;
for (const Arc& a : arcs) {
//std::cout << "arc[" << i << "] : " << a << "\n";
if (a.lo > hi) union_area += Arc(hi, a.lo, disk).green(), hi = a.hi;
else hi = std::max(hi, a.hi);
}
}
return union_area;
}
void solve() {
std::cin.tie(0)->sync_with_stdio(0);
std::cout.tie(0);
std::cout << std::fixed;
std::cout.precision(3);
int ret = 0;
std::cin >> N;
std::vector<Circle> tmp(N);
std::vector<bool> V(N, 0);
for (Circle& c : tmp) std::cin >> c;
for (int i = 0; i < N; i++) {//remove
if (V[i]) continue;
for (int j = 0; j < N; j++) {
if (i < j && tmp[i] == tmp[j]) V[i] = 1;
if (tmp[i] < tmp[j]) V[i] = 1;
if (tmp[j] < tmp[i]) V[j] = 1;
}
}
Disks VC;
for (int i = 0; i < N; i++) {
if (!V[i]) VC.push_back(tmp[i]);
if (V[i]) ret++;
}
int sz = VC.size();
//std::cout << "sz : " << sz << "\n";
ld U = union_except_x(-1, VC);
//std::cout << "U : " << U << "\n";
for (int x = 0; x < sz; x++) {
ld A = union_except_x(x, VC);
//std::cout << "U : " << U << " A : " << A << "\n";
ret += zero(U - A);//no-dabwon
}
std::cout << ret << "\n";
}
int main() { solve(); return 0; }//boj10900 lonely mdic
/*
3
3 0 4
-3 0 4
0 0 2
5
0 0 1
1 1 1
-1 1 1
-1 -1 1
1 -1 1
9
3 0 4
-3 0 4
0 0 2
9 0 4
6 0 2
15 0 4
12 0 2
21 0 4
18 0 2
5
1000 1000 1415
1000 -1000 1415
-1000 -1000 1415
-1000 1000 1415
0 0 1
5
1000 1000 1414
1000 -1000 1414
-1000 -1000 1414
-1000 1000 1414
0 0 1
*/
//ld union_except_x(const int& x, std::vector<Circle>& VC) {
// ld union_area = 0;
// int sz = VC.size();
// for (int i = 0; i < sz; i++) {
// if (i == x) continue;
// Circle& disk = VC[i];
// Arcs arcs;
// for (int j = 0; j < sz; j++) {
// if (j == x || j == i) continue;
// Pos& ca = VC[i].c, cb = VC[j].c;
// ll ra = VC[i].r, rb = VC[j].r;
// Pos vec = cb - ca;//vec a -> b
// ld distance = vec.mag();
// ld X = (ra * ra - rb * rb + vec.Euc()) / (2 * distance);
//
// if (X < -ra + TOL || X > ra - TOL) continue;
//
// ld ratio = sqrt(ra * ra - X * X);
// Pos w = vec * X / distance;
// Pos h = ~vec.unit() * ratio;
// ld lo = (w - h).rad(), hi = (w + h).rad();
//
// Arc a1, a2;
// if (sign(hi - lo) >= 0) {
// a1 = Arc(lo, hi, disk);
// arcs.push_back(a1);
// }
// else {
// a1 = Arc(lo, PI * 2, disk);
// a2 = Arc(0, hi, disk);
// arcs.push_back(a1);
// arcs.push_back(a2);
// }
// }
//
// if (!arcs.size()) {
// //std::cout << "i : " << i << "\n";
// union_area += disk.A();
// continue;
// }
//
// std::sort(arcs.begin(), arcs.end());
// arcs.push_back(Arc(2 * PI, 2 * PI, disk));
// ld hi = 0;
// for (const Arc& a : arcs) {
// //std::cout << "arc[" << i << "] : " << a << "\n";
// if (a.lo > hi) union_area += Arc(hi, a.lo, disk).green(), hi = a.hi;
// else hi = std::max(hi, a.hi);
// }
// }
// return union_area;
//}
Compilation message
L.cpp: In function 'ld union_except_x(const int&, std::vector<Circle>&)':
L.cpp:135:9: warning: unused variable 'ca' [-Wunused-variable]
135 | Pos& ca = VC[i].c, cb = VC[j].c;
| ^~
L.cpp:135:23: warning: variable 'cb' set but not used [-Wunused-but-set-variable]
135 | Pos& ca = VC[i].c, cb = VC[j].c;
| ^~
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
26 ms |
348 KB |
Output is correct |
2 |
Correct |
19 ms |
344 KB |
Output is correct |
3 |
Correct |
183 ms |
508 KB |
Output is correct |
4 |
Incorrect |
164 ms |
344 KB |
Output isn't correct |
5 |
Halted |
0 ms |
0 KB |
- |