Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Слава Україні, Героям слава
- #include <bits/stdc++.h>
- using namespace std;
- #define st first
- #define nd second
- #define pb push_back
- #define cl(x,v) memset((x), (v), sizeof(x))
- #define db(x) cerr << #x << " == " << x << endl
- #define dbs(x) cerr << x << endl
- #define _ << ", " <<
- typedef long long ll;
- typedef long double ld;
- typedef pair<int, int> pii;
- typedef pair<int, pii> piii;
- typedef pair<ll, ll> pll;
- typedef pair<ll, pll> plll;
- typedef vector<int> vi;
- typedef vector <vi> vii;
- const ld EPS = 1e-7, PI = acos(-1.);
- const ll LINF = 0x3f3f3f3f3f3f3f3f;
- const int INF = 0x3f3f3f3f, MOD = 1e9 + 7;
- const int N = 1e5 + 5;
- //for big coordinates change to long long
- typedef long double type;
- /* The functions above are for:
- ge => greater or equal
- le => lesser or equal
- eq => equal
- sign => sign of a number (+ or -)
- */
- bool ge(type x, type y) { return x > y - EPS; }
- bool le(type x, type y) { return x - EPS < y; }
- bool eq(type x, type y) { return ge(x, y) and le(x, y); }
- int sign(type x) { return ge(x, 0) - le(x, 0); }
- struct point {
- type x, y;
- point() : x(0), y(0) {}
- point(type _x, type _y) : x(_x), y(_y) {}
- point operator -() { return point(-x, -y); }
- point operator +(point p) { return point(x + p.x, y + p.y); }
- point operator -(point p) { return point(x - p.x, y - p.y); }
- point operator *(type k) { return point(x * k, y * k); }
- point operator /(type k) { return point(x / k, y / k); }
- //inner product
- type operator *(point p) { return x * p.x + y * p.y; }
- //cross product
- type operator %(point p) { return x * p.y - y * p.x; }
- bool operator ==(const point& p) const { return x == p.x and y == p.y; }
- bool operator !=(const point& p) const { return x != p.x or y != p.y; }
- bool operator <(const point& p) const { return (x < p.x) or (x == p.x and y < p.y); }
- // 0 => same direction
- // 1 => other is on the left
- //-1 => other is on the right
- int dir(point origin, point other) {
- type d = (*this - origin) % (other - origin);
- return ge(d, 0) - le(d, 0);
- }
- bool on_seg(point p, point q) {
- if (this->dir(p, q)) return 0;
- return ge(x, min(p.x, q.x)) and le(x, max(p.x, q.x)) and ge(y, min(p.y, q.y)) and le(y, max(p.y, q.y));
- }
- ld abs() { return sqrt(x * x + y * y); }
- type abs2() { return x * x + y * y; }
- ld dist(point q) { return (*this - q).abs(); }
- type dist2(point q) { return (*this - q).abs2(); }
- ld arg() { return atan2l(y, x); }
- // Project point on vector y
- point project(point y) { return y * ((*this * y) / (y * y)); }
- // Project point on line generated by points x and y
- point project(point x, point y) { return x + (*this - x).project(y - x); }
- ld dist_line(point x, point y) { return dist(project(x, y)); }
- ld dist_seg(point x, point y) {
- return project(x, y).on_seg(x, y) ? dist_line(x, y) : min(dist(x), dist(y));
- }
- point rotate(ld sin, ld cos) { return point(cos * x - sin * y, sin * x + cos * y); }
- point rotate(ld a) { return rotate(sin(a), cos(a)); }
- // rotate around the argument of vector p
- point rotate(point p) { return rotate(p.y / p.abs(), p.x / p.abs()); }
- };
- int direction(point origin, point p, point other) { return p.dir(origin, other); }
- //rotates 90 degrees counter clockwise
- point rotate_ccw90(point p) { return point(-p.y, p.x); }
- //rotates 90 degrees clockwise
- point rotate_cw90(point p) { return point(p.y, -p.x); }
- //for reading purposes avoid using * and % operators, use the functions below:
- type dot(point p, point q) { return p.x * q.x + p.y * q.y; }
- type cross(point p, point q) { return p.x * q.y - p.y * q.x; }
- //twice the area of a triangle
- type area_2(point a, point b, point c) { return cross(a, b) + cross(b, c) + cross(c, a); }
- /*Compares the absolute angle defined by (a1 and b1) vs angle defined by (a2 and b2)
- 1 : bigger
- -1 : smaller
- 0 : equal
- Example:
- angle_less(point(1, 0) , point(0, 1), point(-1, 0), point(-1, -1)) == 1
- the angle formed by the two first vectors is 90 degrees
- the angle formed by the two last vectors is 45 degrees
- */
- int angle_less(const point& a1, const point& b1, const point& a2, const point& b2) {
- point p1(dot(a1, b1), abs(cross(a1, b1)));
- point p2(dot(a2, b2), abs(cross(a2, b2)));
- if (cross(p1, p2) < 0) return 1;
- if (cross(p1, p2) > 0) return -1;
- return 0;
- }
- ostream& operator<<(ostream& os, const point& p) {
- os << "(" << p.x << "," << p.y << ")";
- return os;
- }
- point project_point_line(point c, point a, point b) {
- ld r = dot(b - a, b - a);
- if (fabs(r) < EPS) return a;
- return a + (b - a) * dot(c - a, b - a) / dot(b - a, b - a);
- }
- point project_point_ray(point c, point a, point b) {
- ld r = dot(b - a, b - a);
- if (fabs(r) < EPS) return a;
- r = dot(c - a, b - a) / r;
- if (le(r, 0)) return a;
- return a + (b - a) * r;
- }
- point project_point_segment(point c, point a, point b) {
- ld r = dot(b - a, b - a);
- if (fabs(r) < EPS) return a;
- r = dot(c - a, b - a) / r;
- if (le(r, 0)) return a;
- if (ge(r, 1)) return b;
- return a + (b - a) * r;
- }
- ld distance_point_line(point c, point a, point b) {
- return c.dist2(project_point_line(c, a, b));
- }
- ld distance_point_ray(point c, point a, point b) {
- return c.dist2(project_point_ray(c, a, b));
- }
- ld distance_point_segment(point c, point a, point b) {
- return c.dist2(project_point_segment(c, a, b));
- }
- //not tested
- ld distance_point_plane(ld x, ld y, ld z,
- ld a, ld b, ld c, ld d)
- {
- return fabs(a * x + b * y + c * z - d) / sqrt(a * a + b * b + c * c);
- }
- bool lines_parallel(point a, point b, point c, point d) {
- return fabs(cross(b - a, d - c)) < EPS;
- }
- bool lines_collinear(point a, point b, point c, point d) {
- return lines_parallel(a, b, c, d)
- && fabs(cross(a - b, a - c)) < EPS
- && fabs(cross(c - d, c - a)) < EPS;
- }
- point lines_intersect(point p, point q, point a, point b) {
- point r = q - p, s = b - a, c(p % q, a % b);
- if (eq(r % s, 0)) return point(LINF, LINF);
- return point(point(r.x, s.x) % c, point(r.y, s.y) % c) / (r % s);
- }
- //be careful: test line_line_intersection before using this function
- point compute_line_intersection(point a, point b, point c, point d) {
- b = b - a; d = c - d; c = c - a;
- assert(dot(b, b) > EPS && dot(d, d) > EPS);
- return a + b * cross(c, d) / cross(b, d);
- }
- bool line_line_intersect(point a, point b, point c, point d) {
- if (!lines_parallel(a, b, c, d)) return true;
- if (lines_collinear(a, b, c, d)) return true;
- return false;
- }
- //rays in direction a -> b, c -> d
- bool ray_ray_intersect(point a, point b, point c, point d) {
- if (a.dist2(c) < EPS || a.dist2(d) < EPS ||
- b.dist2(c) < EPS || b.dist2(d) < EPS) return true;
- if (lines_collinear(a, b, c, d)) {
- if (ge(dot(b - a, d - c), 0)) return true;
- if (ge(dot(a - c, d - c), 0)) return true;
- return false;
- }
- if (!line_line_intersect(a, b, c, d)) return false;
- point inters = lines_intersect(a, b, c, d);
- if (ge(dot(inters - c, d - c), 0) && ge(dot(inters - a, b - a), 0)) return true;
- return false;
- }
- bool segment_segment_intersect(point a, point b, point c, point d) {
- if (a.dist2(c) < EPS || a.dist2(d) < EPS ||
- b.dist2(c) < EPS || b.dist2(d) < EPS) return true;
- int d1, d2, d3, d4;
- d1 = direction(a, b, c);
- d2 = direction(a, b, d);
- d3 = direction(c, d, a);
- d4 = direction(c, d, b);
- if (d1 * d2 < 0 and d3 * d4 < 0) return 1;
- return a.on_seg(c, d) or b.on_seg(c, d) or
- c.on_seg(a, b) or d.on_seg(a, b);
- }
- bool segment_line_intersect(point a, point b, point c, point d) {
- if (!line_line_intersect(a, b, c, d)) return false;
- point inters = lines_intersect(a, b, c, d);
- if (inters.on_seg(a, b)) return true;
- return false;
- }
- //ray in direction c -> d
- bool segment_ray_intersect(point a, point b, point c, point d) {
- if (a.dist2(c) < EPS || a.dist2(d) < EPS ||
- b.dist2(c) < EPS || b.dist2(d) < EPS) return true;
- if (lines_collinear(a, b, c, d)) {
- if (c.on_seg(a, b)) return true;
- if (ge(dot(d - c, a - c), 0)) return true;
- return false;
- }
- if (!line_line_intersect(a, b, c, d)) return false;
- point inters = lines_intersect(a, b, c, d);
- if (!inters.on_seg(a, b)) return false;
- if (ge(dot(inters - c, d - c), 0)) return true;
- return false;
- }
- //ray in direction a -> b
- bool ray_line_intersect(point a, point b, point c, point d) {
- if (a.dist2(c) < EPS || a.dist2(d) < EPS ||
- b.dist2(c) < EPS || b.dist2(d) < EPS) return true;
- if (!line_line_intersect(a, b, c, d)) return false;
- point inters = lines_intersect(a, b, c, d);
- if (!line_line_intersect(a, b, c, d)) return false;
- if (ge(dot(inters - a, b - a), 0)) return true;
- return false;
- }
- ld distance_segment_line(point a, point b, point c, point d) {
- if (segment_line_intersect(a, b, c, d)) return 0;
- return min(distance_point_line(a, c, d), distance_point_line(b, c, d));
- }
- ld distance_segment_ray(point a, point b, point c, point d) {
- if (segment_ray_intersect(a, b, c, d)) return 0;
- ld min1 = distance_point_segment(c, a, b);
- ld min2 = min(distance_point_ray(a, c, d), distance_point_ray(b, c, d));
- return min(min1, min2);
- }
- ld distance_segment_segment(point a, point b, point c, point d) {
- if (segment_segment_intersect(a, b, c, d)) return 0;
- ld min1 = min(distance_point_segment(c, a, b), distance_point_segment(d, a, b));
- ld min2 = min(distance_point_segment(a, c, d), distance_point_segment(b, c, d));
- return min(min1, min2);
- }
- ld distance_ray_line(point a, point b, point c, point d) {
- if (ray_line_intersect(a, b, c, d)) return 0;
- ld min1 = distance_point_line(a, c, d);
- return min1;
- }
- ld distance_ray_ray(point a, point b, point c, point d) {
- if (ray_ray_intersect(a, b, c, d)) return 0;
- ld min1 = min(distance_point_ray(c, a, b), distance_point_ray(a, c, d));
- return min1;
- }
- ld distance_line_line(point a, point b, point c, point d) {
- if (line_line_intersect(a, b, c, d)) return 0;
- return distance_point_line(a, c, d);
- }
- struct circle {
- point c;
- ld r;
- circle() { c = point(); r = 0; }
- circle(point _c, ld _r) : c(_c), r(_r) {}
- ld area() { return acos(-1.0) * r * r; }
- ld chord(ld rad) { return 2 * r * sin(rad / 2.0); }
- ld sector(ld rad) { return 0.5 * rad * area() / acos(-1.0); }
- bool intersects(circle other) {
- return le(c.dist(other.c), r + other.r);
- }
- bool contains(point p) { return le(c.dist(p), r); }
- pair<point, point> getTangentPoint(point p) {
- ld d1 = c.dist(p), theta = asin(r / d1);
- point p1 = (c - p).rotate(-theta);
- point p2 = (c - p).rotate(theta);
- p1 = p1 * (sqrt(d1 * d1 - r * r) / d1) + p;
- p2 = p2 * (sqrt(d1 * d1 - r * r) / d1) + p;
- return make_pair(p1, p2);
- }
- };
- circle circumcircle(point a, point b, point c) {
- circle ans;
- point u = point((b - a).y, -(b - a).x);
- point v = point((c - a).y, -(c - a).x);
- point n = (c - b) * 0.5;
- ld t = cross(u, n) / cross(v, u);
- ans.c = ((a + c) * 0.5) + (v * t);
- ans.r = ans.c.dist(a);
- return ans;
- }
- point compute_circle_center(point a, point b, point c) {
- //circumcenter
- b = (a + b) / 2;
- c = (a + c) / 2;
- return compute_line_intersection(b, b + rotate_cw90(a - b), c, c + rotate_cw90(a - c));
- }
- int inside_circle(point p, circle c) {
- if (fabs(p.dist(c.c) - c.r) < EPS) return 1;
- else if (p.dist(c.c) < c.r) return 0;
- else return 2;
- } //0 = inside/1 = border/2 = outside
- circle incircle(point p1, point p2, point p3) {
- ld m1 = p2.dist(p3);
- ld m2 = p1.dist(p3);
- ld m3 = p1.dist(p2);
- point c = (p1 * m1 + p2 * m2 + p3 * m3) * (1 / (m1 + m2 + m3));
- ld s = 0.5 * (m1 + m2 + m3);
- ld r = sqrt(s * (s - m1) * (s - m2) * (s - m3)) / s;
- return circle(c, r);
- }
- circle minimum_circle(vector<point> p) {
- random_shuffle(p.begin(), p.end());
- circle C = circle(p[0], 0.0);
- for (int i = 0; i < (int)p.size(); i++) {
- if (C.contains(p[i])) continue;
- C = circle(p[i], 0.0);
- for (int j = 0; j < i; j++) {
- if (C.contains(p[j])) continue;
- C = circle((p[j] + p[i]) * 0.5, 0.5 * p[j].dist(p[i]));
- for (int k = 0; k < j; k++) {
- if (C.contains(p[k])) continue;
- C = circumcircle(p[j], p[i], p[k]);
- }
- }
- }
- return C;
- }
- // compute intersection of line through points a and b with
- // circle centered at c with radius r > 0
- vector<point> circle_line_intersection(point a, point b, point c, ld r) {
- vector<point> ret;
- b = b - a;
- a = a - c;
- ld A = dot(b, b);
- ld B = dot(a, b);
- ld C = dot(a, a) - r * r;
- ld D = B * B - A * C;
- if (D < -EPS) return ret;
- ret.push_back(c + a + b * (sqrt(D + EPS) - B) / A);
- if (D > EPS)
- ret.push_back(c + a + b * (-B - sqrt(D)) / A);
- return ret;
- }
- vector<point> circle_circle_intersection(point a, point b, ld r, ld R) {
- vector<point> ret;
- ld d = sqrt(a.dist2(b));
- if (d > r + R || d + min(r, R) < max(r, R)) return ret;
- ld x = (d * d - R * R + r * r) / (2 * d);
- ld y = sqrt(r * r - x * x);
- point v = (b - a) / d;
- ret.push_back(a + v * x + rotate_ccw90(v) * y);
- if (y > 0)
- ret.push_back(a + v * x - rotate_ccw90(v) * y);
- return ret;
- }
- //GREAT CIRCLE
- double gcTheta(double pLat, double pLong, double qLat, double qLong) {
- pLat *= acos(-1.0) / 180.0; pLong *= acos(-1.0) / 180.0; // convert degree to radian
- qLat *= acos(-1.0) / 180.0; qLong *= acos(-1.0) / 180.0;
- return acos(cos(pLat) * cos(pLong) * cos(qLat) * cos(qLong) +
- cos(pLat) * sin(pLong) * cos(qLat) * sin(qLong) +
- sin(pLat) * sin(qLat));
- }
- double gcDistance(double pLat, double pLong, double qLat, double qLong, double radius) {
- return radius * gcTheta(pLat, pLong, qLat, qLong);
- }
- // getting the angle at point b
- long double angle(point a, point b, point c) {
- long double ab = a.dist(b), ac = a.dist(c), bc = b.dist(c);
- long double tmp = ab * ab + bc * bc - ac * ac;
- tmp /= 2 * ab * bc;
- return fabs(acosl(tmp));
- }
- int main() {
- ios_base::sync_with_stdio(false);
- cin.tie(nullptr);
- cout << setprecision(15) << fixed;
- int n;
- cin >> n;
- vector<point> v(n);
- for(int i = 0; i < n; i++) {
- cin >> v[i].x >> v[i].y;
- }
- long double ans = 0;
- for(int i = 0; i < n; i++) {
- // cout << i << "\n";
- point pr = v[(i - 1 + n) % n], prr = v[(i - 2 + n) % n], pl = v[(i + 1) % n], pll = v[(i + 2) % n];
- point mid = (pl + pr) / 2;
- long double base = pl.dist(v[i]) + pr.dist(v[i]);
- long double rad = pl.dist(pr) / 2;
- point p = mid + rotate_ccw90((pr - pl) / 2);
- if(direction(pll, pl, p) == -1 and direction(prr, pr, p) == 1 and ge(angle(pll, pl, p), PI / 2) and ge(angle(prr, pr, p), PI / 2)) {
- // cout << "on circle\n";
- // cout << rad * 2 * sqrtl(2) - base << "\n";
- ans = max(ans, rad * 2 * sqrtl(2) - base);
- }
- if(line_line_intersect(pll, pl, prr, pr)) {
- point inter = lines_intersect(pll, pl, prr, pr);
- if(direction(pl, pr, inter) == 1 and ge(angle(pl, inter, pr), PI / 2)) {
- // cout << "line line intersect\n";
- // cout << pl.dist(inter) + pr.dist(inter) - base << "\n";
- // cout << inter << "\n";
- // cout << direction(pl, pr, inter) << "\n";
- ans = max(ans, pl.dist(inter) + pr.dist(inter) - base);
- }
- }
- //maybe middle do not work so grab the arc
- //each point will have a left boundary and right boundary which by default is arc(pl, pr), but maybe the possible arc is smaller than the whole arc
- point pr_lb = pl, pr_rb = pr, pl_lb = pl, pl_rb = pr;
- auto inter = circle_line_intersection(pl, pll, mid, rad);
- for(auto a : inter) {
- if(direction(prr, pr, a) == 1 and direction(pl, pr, a) != -1) {
- // cout << "circle line left\n";
- // cout << pl.dist(a) + pr.dist(a) - base << "\n";
- // cout << a << "\n";
- ans = max(ans, pl.dist(a) + pr.dist(a) - base);
- pl_lb = a;
- }
- }
- inter = circle_line_intersection(pr, prr, mid, rad);
- for(auto a : inter) {
- if (direction(pll, pl, a) == -1 and direction(pl, pr, a) != -1) {
- // cout << "circle line right\n";
- // cout << pl.dist(a) + pr.dist(a) - base << "\n";
- // cout << a << "\n";
- ans = max(ans, pl.dist(a) + pr.dist(a) - base);
- pr_rb = a;
- }
- }
- inter = circle_line_intersection(pr, pr + rotate_ccw90(pr - prr), mid, rad);
- for(auto a : inter) {
- if(eq(a.dist(pr), 0)) continue;
- if(direction(pl, pr, a) != -1) pr_lb = a;
- }
- inter = circle_line_intersection(pl, pl + rotate_cw90(pl - pll), mid, rad);
- for(auto a : inter) {
- if(eq(a.dist(pl), 0)) continue;
- if(direction(pl, pr, a) != -1) pl_rb = a;
- }
- //use boundaries to update answer, it will either improve or stay the same, e.g. boundary is pl or pr.
- //for each boundary point it must be inside the boundary defined by the other point, e.g. pl_al must be inside the arc(pr_al, pr_ar).
- //pr_lb
- if (direction(mid, pl_lb, pr_lb) != 1 and direction(mid, pl_rb, pr_lb) != -1) ans = max(ans, pl.dist(pr_lb) + pr.dist(pr_lb) - base);
- //pr_rb
- if (direction(mid, pl_lb, pr_rb) != 1 and direction(mid, pl_rb, pr_rb) != -1) ans = max(ans, pl.dist(pr_rb) + pr.dist(pr_rb) - base);
- //pl_lb
- if (direction(mid, pr_lb, pl_lb) != 1 and direction(mid, pr_rb, pl_lb) != -1) ans = max(ans, pl.dist(pl_lb) + pr.dist(pl_lb) - base);
- //pl_rb
- if (direction(mid, pr_lb, pl_rb) != 1 and direction(mid, pr_rb, pl_rb) != -1) ans = max(ans, pl.dist(pl_rb) + pr.dist(pl_rb) - base);
- }
- cout << ans << "\n";
- return 0;
- }
Add Comment
Please, Sign In to add comment