QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#226174 | #5060. Circle | hocky | WA | 765ms | 4776kb | C++20 | 8.8kb | 2023-10-25 17:37:21 | 2023-10-25 17:37:21 |
Judging History
answer
/*
Author : Hocky Yudhiono
Rab 25 Okt 2023 02:25:01
*/
#pragma GCC optimize("no-stack-protector,O3,unroll-loops")
#include "bits/stdc++.h"
using namespace std;
typedef long long LL;
typedef vector<int> vi;
typedef vector<LL> vl;
typedef vector<vi> vvi;
typedef vector<vl> vvl;
typedef pair<int, int> PII;
typedef pair<int, int> pii;
typedef pair<LL, LL> PLL;
typedef pair<LL, LL> pll;
typedef long double ld;
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define popf pop_front
#define pf push_front
#define popb pop_back
#define pb push_back
#define fi first
#define se second
const int INFMEM = 63;
// Do dir^1 to get reverse direction
const int dx[8] = {0, 0, 1, -1, 1, -1, 1, -1};
const int dy[8] = {1, -1, 0, 0, 1, -1, -1, 1};
const char dch[4] = {'R', 'L', 'D', 'U'};
// Do (dir + 2)%4 to get reverse direction
// const int dx[8] = {-1,0,1,0,-1,1,1,-1};
// const int dy[8] = {0,1,0,-1,1,1,-1,-1};
// const char dch[4] = {'U','R','D','L'};
const double PI = 3.141592653589793;
inline void fasterios() {
cin.tie(0)->sync_with_stdio(0);
cin.exceptions(cin.failbit);
}
#define endl '\n'
const int MOD = 1000000007;
// const int MOD = 998244353;
template <class T> int sgn(T x) { return (x > 0) - (x < 0); }
template<class T>
struct Point {
typedef Point P;
T x, y;
explicit Point(T X = 0, T Y = 0) : x(X), y(Y) {}
bool operator<(P p) const { return tie(x, y) < tie(p.x, p.y); }
bool operator==(P p) const { return tie(x, y) == tie(p.x, p.y); }
P operator+(P p) const { return P(x + p.x, y + p.y); }
P operator-(P p) const { return P(x - p.x, y - p.y); }
P operator*(T d) const { return P(x * d, y * d); }
P operator/(T d) const { return P(x / d, y / d); }
T dot(P p) const { return x * p.x + y * p.y; }
T cross(P p) const { return x * p.y - y * p.x; }
T cross(P a, P b) const { return (a - *this).cross(b - *this); }
// return the orientation of (*this,a,b), 1 if ccw
int ccw(P a, P b) const { return sgn((a - *this).cross(b - *this)); }
T dist2() const { return x * x + y * y; }
double dist() const { return sqrt((double)dist2()); }
// angle to x-axis in interval [-pi, pi]
double angle() const { return atan2(y, x); }
P unit() const { return *this / dist(); } // makes dist()=1
P perp() const { return P(-y, x); } // rotates +90 degrees
P normal() const { return perp().unit(); }
// returns point rotated 'a' radians ccw around the origin
P rotate(double a) const {
return P(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a));
}
friend ostream& operator<<(ostream& os, P p) {
return os << "" << p.x << " " << p.y << "";
}
};
typedef Point<double> P;
typedef double db;
template<class P>
pair<int, P> lineInter(P s1, P e1, P s2, P e2) {
auto d = (e1 - s1).cross(e2 - s2);
if (d == 0) // if parallel
return { -(s1.cross(e1, s2) == 0), P(0, 0)};
auto p = s2.cross(e1, e2), q = s2.cross(e2, s1);
return {1, (s1 * p + e1 * q) / d};
}
template<class P>
int sideOf(P s, P e, P p) { return sgn(s.cross(e, p)); }
template<class P>
int sideOf(const P& s, const P& e, const P& p, double eps) {
auto a = (e - s).cross(p - s);
double l = (e - s).dist() * eps;
return (a > l) - (a < -l);
}
typedef array<P, 2> Line;
#define sp(a) a[0], a[1]
#define ang(a) (a[1] - a[0]).angle()
int angDiff(Line a, Line b) { return sgn(ang(a) - ang(b)); }
bool cmp(Line a, Line b) {
int s = angDiff(a, b);
return (s ? s : sideOf(sp(a), b[0])) < 0;
}
vector<P> halfPlaneIntersection(vector<Line> vs) {
const double EPS = sqrt(2) * 1e-8;
sort(all(vs), cmp);
vector<Line> deq(sz(vs) + 5);
vector<P> ans(sz(vs) + 5);
deq[0] = vs[0];
int ah = 0, at = 0, n = sz(vs);
rep(i, 1, n + 1) {
if (i == n) vs.push_back(deq[ah]);
if (angDiff(vs[i], vs[i - 1]) == 0) continue;
while (ah < at && sideOf(sp(vs[i]), ans[at - 1], EPS) < 0)
at--;
while (i != n && ah < at && sideOf(sp(vs[i]), ans[ah], EPS) < 0)
ah++;
auto res = lineInter(sp(vs[i]), sp(deq[at]));
if (res.first != 1) continue;
ans[at++] = res.second, deq[at] = vs[i];
}
if (at - ah <= 2) return {};
return {ans.begin() + ah, ans.begin() + at};
}
typedef double db;
typedef pair<P, db> Circle;
const double TAU = 2 * PI;
namespace CIRUT {
const int LIM = 1000;
Circle isi[LIM + 18];
int n, p[LIM * 4 + 18], q[LIM * 4 + 18], qt, ttmp;
db ans[LIM + 18], alp[LIM * 4 + 18];
void reset(int _n) {
n = _n; qt = ttmp = 0;
rep(i, 0, (n + 1) * 4 + 2) p[i] = q[i] = alp[i] = 0;
rep(i, 0, n + 1) ans[i] = 0, isi[i] = Circle();
}
int eps(db x) {
return x < -1e-8 ? -1 : x > 1e-8;
}
int cmpor(const void *i, const void *j) {
return (ttmp = eps(alp[*(int *)i] - alp[*(int *)j])) ? ttmp : q[*(int *)j] - q[*(int *)i];
}
int judge(db d, int r0, int r1) {
if (eps(d - r0 - r1) >= 0) return -1;
if (eps(d + r1 - r0) <= 0) return 0;
if (eps(d + r0 - r1) <= 0) return 1;
return 2;
}
void inter(int a, int b, int dx, int dy, db d, db &a0, db &a1) {
db da = acos((isi[a].se * isi[a].se + d * d - isi[b].se * isi[b].se) * 0.5 / (isi[a].se * d));
db ba = atan2(dy, dx); a0 = ba - da, a1 = ba + da;
if (a0 < 0) a0 += TAU;
if (a1 < 0) a1 += TAU;
}
db calcarea(int a, db a0, db a1) {
db da = a1 - a0;
if (!eps(da)) return 0;
db x0 = isi[a].fi.x + isi[a].se * cos(a0), y0 = isi[a].fi.y + isi[a].se * sin(a0);
db x1 = isi[a].fi.x + isi[a].se * cos(a1), y1 = isi[a].fi.y + isi[a].se * sin(a1);
return isi[a].se * isi[a].se * (da - sin(da)) + (x0 * y1 - x1 * y0);
}
void calc(int X) {
int covered = 1, dx, dy;
db d; qt = 0;
for (int i = 1, tmp; i <= n; ++i)
if (X != i && (dx = isi[i].fi.x - isi[X].fi.x, dy = isi[i].fi.y - isi[X].fi.y, tmp = judge(d = sqrt(dx * dx + dy * dy), isi[X].se, isi[i].se)) > 0) {
if (tmp == 1) ++covered;
else {
inter(X, i, dx, dy, d, alp[qt + 1], alp[qt + 2]);
q[++qt] = 1, p[qt] = qt;
q[++qt] = -1, p[qt] = qt;
if (eps(alp[qt - 1] - alp[qt]) > 0) {
alp[++qt] = 0, q[qt] = 1, p[qt] = qt;
alp[++qt] = TAU, q[qt] = -1, p[qt] = qt;
}
}
}
if (!qt) {ans[covered] += isi[X].se * isi[X].se * TAU; return;}
qsort(p + 1, qt, sizeof(p[0]), cmpor);
ans[covered] += calcarea(X, 0, alp[p[1]]) + calcarea(X, alp[p[qt]], TAU);
for (int i = 1; i < qt; ++i)
covered += q[p[i]], ans[covered] += calcarea(X, alp[p[i]], alp[p[i + 1]]);
}
void solve() {
rep(i, 1, n + 1) calc(i);
rep(i, 1, n + 1) ans[i] -= ans[i + 1], ans[i] *= 0.5;
}
}
// Don't forget to read all the inputs before returning!!!
int solve() {
LL n; cin >> (n);
LL rr; cin >> (rr);
double r = rr;
vector <P> isi(n);
trav(cur, isi) {
LL a; cin >> (a);
LL b; cin >> (b);
cur.x = a;
cur.y = b;
}
if (n <= 50) {
// Solve using cirut
CIRUT::reset(n + 1);
for (int i = 1; i <= n; i++) {
CIRUT::isi[i] = {isi[i - 1], r};
}
CIRUT::solve();
cout << CIRUT::ans[n] << endl;
return 0;
}
vector <Line> halfplane;
vector <P> centers;
rep(i, 0, n) {
// make a circle with radius r
auto &cur = isi[i];
auto &nx = isi[(i + 1) % n];
db dist = (cur - nx).dist() / 2;
if (fabs(dist / r) >= 1) {
cout << 0 << endl;
return 0;
}
auto alpha = acos(dist / r);
if (isnan(alpha)) {
cout << 0 << endl;
return 0;
}
//masukin 4 kotak
// Kotak kanan
{
auto vec1 = nx - cur;
auto pvec1 = vec1.perp();
vec1 = vec1.unit() * r + cur;
halfplane.pb({vec1, vec1 + pvec1});
}
// Kotak kiri
{
auto vec1 = cur - nx;
auto pvec1 = vec1.perp();
vec1 = vec1.unit() * r + nx;
halfplane.pb({vec1, vec1 + pvec1});
}
auto vec = (nx - cur);
auto center1 = cur + vec.rotate(alpha).unit() * r;
auto center2 = cur + vec.rotate(-alpha).unit() * r;
halfplane.pb({center1, center1 + (cur - nx)});
halfplane.pb({center2, center2 + (nx - cur)});
centers.pb(center1);
// cout << center2 << endl;
}
rep(i,0,sz(centers)){
halfplane.pb({centers[i], centers[(i + 1)%sz(centers)]});
}
// trav(cur, halfplane) {
// cout << 2 << " " << 1 << endl;
// cout << cur[0] << " " << cur[1] << endl;
// }
auto res = halfPlaneIntersection(halfplane);
double ans = 0;
rep(i, 0, sz(res)) {
ans += res[i].cross(res[(i + 1) % sz(res)]);
}
cout << ans / 2 << endl;
// cout << (ans) / 2 << '\n';
return 0;
}
int main() {
fasterios();
cout << fixed << setprecision(9);
LL testCases = 1, tc = 0;
cin >> (testCases);
while (++tc <= testCases) {
// cout << "Case #" << tc << ": ";
solve();
}
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 1ms
memory: 4136kb
input:
3 4 1 0 0 1 0 1 1 0 1 4 1 0 0 1 1 0 2 -1 1 4 100 0 0 1 0 1 1 0 1
output:
0.315146744 0.000000000 31016.928202571
result:
ok 3 numbers
Test #2:
score: 0
Accepted
time: 179ms
memory: 3712kb
input:
200000 1 2 616 2935 1 3 1708 -4771 1 4 4133 2145 1 5 3093 -8563 1 6 -6703 -7258 1 7 -8847 -6629 1 8 -9278 -3604 1 9 3958 -8464 1 10 -7019 4795 1 11 -4181 4366 1 12 -8801 -3294 1 13 -8106 -4512 1 14 -7044 1933 1 15 -5546 -9705 1 16 2755 -6889 1 17 5578 -2779 1 18 3724 -6647 1 19 6530 4628 1 20 -9775 ...
output:
12.566370614 28.274333882 50.265482457 78.539816340 113.097335529 153.938040026 201.061929830 254.469004941 314.159265359 380.132711084 452.389342117 530.929158457 615.752160104 706.858347058 804.247719319 907.920276887 1017.876019763 1134.114947946 1256.637061436 1385.442360233 1520.530844337 1661....
result:
ok 200000 numbers
Test #3:
score: 0
Accepted
time: 211ms
memory: 4088kb
input:
49788 1 1 1 1 2 2 -1 -2 2 0 3 7 -1 -2 3 -1 -1 0 3 11 1 -3 4 -2 4 3 4 4 -3 4 -2 1 5 0 3 3 5 3 -6 1 -5 -5 4 -6 5 -2 2 0 6 13 -6 -2 5 -4 6 -4 7 3 5 5 -3 1 7 13 -8 -2 -2 -7 3 -8 8 -8 7 -4 3 -1 -8 4 6 22 -8 -1 -7 -8 -6 -9 7 -8 6 0 1 7 5 29 -9 0 -3 -10 3 -8 5 6 -3 9 1 1 0 1 2 3 0 -1 1 2 3 5 -1 1 1 -1 2 3 ...
output:
3.141592654 0.460160176 87.107972627 225.814739058 0.000000000 0.000000000 150.180118660 65.330022402 589.961772321 1331.375887990 3.141592654 10.219895118 31.943872526 19.970661395 0.000000000 8.492873198 200.610225250 631.162631043 667.620777787 1.952409257 12.566370614 6.194964160 0.000000000 19....
result:
ok 49788 numbers
Test #4:
score: -100
Wrong Answer
time: 765ms
memory: 4776kb
input:
236 832 25032 -9981 -8425 -9980 -8477 -9979 -8527 -9975 -8619 -9968 -8777 -9956 -8917 -9948 -8993 -9932 -9112 -9910 -9242 -9907 -9258 -9898 -9298 -9887 -9337 -9857 -9438 -9851 -9457 -9819 -9545 -9812 -9559 -9774 -9627 -9745 -9678 -9729 -9699 -9702 -9734 -9671 -9754 -9637 -9772 -9544 -9819 -9534 -982...
output:
0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 0.000000000 ...
result:
wrong answer 1st numbers differ - expected: '615624863.1877460', found: '0.0000000', error = '1.0000000'