Submission #61089988


Source Code Expand

#include <bits/stdc++.h>
#ifdef LOCAL
#include "debug.h"
#else
#define debug(...)
#endif
using namespace std;

template <typename Point>
struct Geometry {
  using T = typename Point::type;
  using point_t = Point;
  static_assert(Point::dim::value == 2);

  static constexpr long double pi = 3.1415926535897932385;

  static Point Rotate(const Point& v, T alpha) {
    T c = cos(alpha);
    T s = sin(alpha);
    return Point(v.x * c - v.y * s, v.x * s + v.y * c);
  }

  static T GetAngle(const Point& u, const Point& v) {
    auto ul = u.Length(), vl = v.Length();
    if (ul <= Point::eps || vl <= Point::eps) return 0;
    T alpha = u * v / ul / vl;
    return acos(alpha);
  }

  static T GetAngleFromX(const Point& P) {
    double ans = atan2(P.y, P.x);
    if (ans < 0.0) ans += 2.0 * pi;
    return ans;
  }

  static T GetTriangularAngle(T a, T b, T c) {
    T t = (a * a + b * b - c * c) / (2 * a * b);
    if (t < -1) t = -1;
    if (t > 1) t = 1;
    return acos(t);
  }

  static bool IsTriangularSame(const std::vector<Point>& a,
                               const std::vector<Point>& b) {
    assert(a.size() == 3 && b.size() == 3);
    std::vector<T> p = {Dist(a[0], a[1]), Dist(a[1], a[2]), Dist(a[0], a[2])};
    std::vector<T> q = {Dist(b[0], b[1]), Dist(b[1], b[2]), Dist(b[0], b[2])};
    sort(p.begin(), p.end());
    sort(q.begin(), q.end());
    for (int i = 0; i < 3; i++) {
      if (abs(p[i] - q[i]) > Point::eps) return false;
    }
    return true;
  }

  struct Line {
    Point p, u;
    Line(Point p_ = Point(0, 0), Point u_ = Point(1, 0)) : p(p_), u(u_) {
      assert(u.Length() > 0);
    }
    operator std::string() const {
      return "Line(p=" + std::string(p) + ", u=" + std::string(u) + ")";
    }
  };

  static bool IsPointOnLine(const Point& a, const Line& l) {
    return abs(l.u % (a - l.p)) <= Point::eps;
  }
  static Point GetProjectionPoint(const Point& a, const Line& l) {
    Point v = a - l.p;
    Point u = l.u / l.u.Length();
    return l.p + (u * v) * u;
  }

  static Point LineToLineIntersection(const Line& l1, const Line& l2) {
    assert(!(l1.u | l2.u));
    auto t = (l1.p - l2.p) % l1.u / (l2.u % l1.u);
    return l2.p + t * l2.u;
  }

  struct HalfLine {
    Point p, u;
    HalfLine(Point p_ = Point(0, 0), Point u_ = Point(1, 0)) : p(p_), u(u_) {
      assert(u.Length() > Point::eps);
    }
  };

  static bool IsPointOnHalfLine(const Point& a, const HalfLine& l) {
    if (Dist(l.p, a) <= Point::eps) return true;
    return (a - l.p) | l.u && (a - l.p) * l.u >= -Point::eps;
  }

  struct Segment {
    Point a, b;
    Segment(Point a_ = Point(0, 0), Point b_ = Point(1, 0)) : a(a_), b(b_) {}
    Line ToLine() const { return Line(a, b - a); }
    operator std::string() {
      return "Segment(" + std::string(a) + ", " + std::string(b) + ")";
    }
  };

  static bool IsPointOnSegment(const Point& p, const Segment& s) {
    if (Dist2(s.a, p) <= Point::eps || Dist2(s.b, p) <= Point::eps) return true;
    return (p - s.a) | (s.b - s.a) && (s.a - p) * (s.b - p) < -Point::eps;
  }

  struct Circle {
    Point c;
    T r;
    Circle(Point c_ = Point(), T r_ = 1) : c(c_), r(r_) {
      assert(r > Point::eps);
    }
    operator std::string() const {
      return "Circle(c=" + std::string(c) + ", r=" + std::to_string(r) + ")";
    }
  };

  static Point Inverse(const Point& o, T r, const Point& a) {
    T da = Dist(o, a);
    assert(da > Point::eps);
    T db = r * r / da;
    return o + (a - o) * db / da;
  }

  static Circle InverseToCircle(const Point& o, T r, const Circle& a) {
    T da = Dist(o, a.c);
    assert(da - a.r > Point::eps);
    T rb = 0.5 * ((1 / (da - a.r)) - (1 / (da + a.r))) * r * r;
    T db = da * rb / a.r;
    T bx = o.x + (a.c.x - o.x) * db / da;
    T by = o.y + (a.c.y - o.y) * db / da;
    return Circle(Point(bx, by), rb);
  }

  static Line InverseToLine(const Point& o, T r, const Circle& a) {
    T da = Dist(o, a.c);
    assert(abs(da - a.r) <= Point::eps);
    Point v = a.c - o;
    Point p = o + v * 2;
    Point p_ = Inverse(o, r, p);
    return Line(p_, Rotate(v, pi / 2));
  }

  static Circle InverseToCircle(const Point& o, T r, const Line& l) {
    Point p = GetProjectionPoint(o, l);
    assert(Dist(o, p) > Point::eps);
    Point p_ = Inverse(o, r, p);
    return Circle((o + p_) / 2, Dist(o, p_) / 2);
  }

  struct Polygon {
    std::vector<Point> ps;
    bool is_convex;
    Polygon(std::vector<Point> ps_ = {}) : ps(ps_), is_convex(false) {}
    Polygon(const Polygon& b) : ps(b.ps), is_convex(b.is_convex) {}
    Polygon(Polygon&& b) : ps(std::move(b.ps)), is_convex(b.is_convex) {}
    operator std::string() {
      std::string s = "Polygon[";
      for (int i = 0; i < ps.size(); i++) {
        if (i > 0) s += ", ";
        s += std::string(ps[i]);
      }
      s += "]";
      return s;
    }
    T GetArea() const {
      assert(ps.size() > 0);
      T sum = 0;
      for (int i = 0; i < (int)ps.size(); i++) {
        sum += 0.5 * ps[i] % ps[(i + 1) % ps.size()];
      }
      return abs(sum);
    }
    bool IsClockwise() const {
      assert(ps.size() > 0);
      T sum = 0;
      for (int i = 0; i < ps.size(); i++) {
        sum += 0.5 * ps[i] % ps[(i + 1) % ps.size()];
      }
      return sum <= Point::eps;
    }
    bool IsConvex() {
      assert(ps.size() >= 2);
      if (IsClockwise()) {
        std::reverse(ps.begin(), ps.end());
      }
      int n = ps.size();
      for (int i = 0; i < n; i++) {
        auto& a = ps[i];
        auto& b = ps[(i + 1) % n];
        auto& c = ps[(i + 2) % n];
        auto u = b - a, v = c - a;
        if (u % v < -Point::eps) return false;
      }
      return true;
    }
    std::vector<Segment> Segments() const {
      std::vector<Segment> segs;
      for (int i = 0; i < ps.size(); i++) {
        auto seg = Segment(ps[i], ps[(i + 1) % ps.size()]);
        segs.push_back(seg);
      }
      return segs;
    }
  };

  static bool IsPointInsidePolygon(const Point& p, const Polygon& poly) {
    if (poly.is_convex) {
      auto& ps = poly.ps;
      auto& o = ps[0];
      Point first = ps[1] - o;
      Point last = ps.back() - o;
      if (first % (p - o) < -Point::eps || last % (p - o) > Point::eps)
        return false;
      auto it = std::lower_bound(
          ps.begin(), ps.end(), p,
          [&](auto& a, auto& b) { return (a - o) % (b - o) >= -Point::eps; });
      int t = it - ps.begin() - 1;
      auto& a = ps[t];
      auto& b = ps[(t + 1) % ps.size()];
      if (IsPointOnSegment(p, {o, a})) return true;
      if (IsPointOnSegment(p, {o, b})) return true;
      if (IsPointOnSegment(p, {a, b})) return true;
      return (p - a) % (b - a) < -Point::eps;
    } else {
      assert(0);
    }
  }

  struct ConnectedArea {
    Polygon out;
    std::vector<Polygon> ins;
    operator std::string() {
      std::string s = "ConnectedArea(";
      s += "out: " + std::string(out);
      s += ", ins: [";
      for (int i = 0; i < ins.size(); i++) {
        if (i > 0) s += ", ";
        s += std::string(ins[i]);
      }
      s += "])";
      return s;
    }
    T GetArea() const {
      T res = out.GetArea();
      for (auto& polygon : ins) {
        res -= polygon.GetArea();
      }
      return res;
    }
    std::vector<Segment> Segments() const {
      std::vector<Segment> segs = out.Segments();
      for (auto& poly : ins) {
        for (auto& seg : poly.Segments()) {
          segs.push_back(seg);
        }
      }
      return segs;
    }
  };

  static Polygon GetConvex(const std::vector<Point>& ps_) {
    auto ps = ps_;
    if (ps.size() <= 2) {
      if (ps.size() == 2 && Dist2(ps[0], ps[1]) <= Point::eps) ps.pop_back();
      Polygon poly(ps);
      poly.is_convex = true;
      return poly;
    }
    int n = ps.size();
    std::rotate(ps.begin(),
                std::min_element(ps.begin(), ps.end(),
                                 [](auto& a, auto& b) {
                                   if (abs(a.y - b.y) > Point::eps)
                                     return a.y < b.y;
                                   return a.x > b.x;
                                 }),
                ps.end());
    Point o = ps[0];
    std::sort(std::next(ps.begin()), ps.end(), [&](auto& a, auto& b) {
      auto t = (a - o) % (b - o);
      if (abs(t) > Point::eps) return t > 0;
      return Dist2(a, o) < Dist2(b, o);
    });
    ps.push_back(o);
    std::vector<Point> res = {ps[0], ps[1]};
    for (int i = 2; i <= n; i++) {
      auto& c = ps[i];
      while (res.size() >= 2) {
        auto& a = *std::next(res.rbegin());
        auto& b = *res.rbegin();
        auto u = b - a, v = c - b;
        auto t = u % v;
        if (t < -Point::eps || (abs(t) <= Point::eps && u * v >= -Point::eps)) {
          res.pop_back();
        } else {
          break;
        }
      }
      if (i < n && Dist2(c, res.back()) > Point::eps) {
        res.push_back(c);
      }
    }
    Polygon poly(res);
    poly.is_convex = true;
    return poly;
  }

  static Polygon Minkowski(Polygon& a, Polygon& b) {
    assert(a.is_convex && b.is_convex);
    int n = a.ps.size(), m = b.ps.size();
    if (n == 0) return b;
    if (m == 0) return a;
    std::vector<Point> res;
    if (std::min(n, m) <= 2) {
      for (auto p1 : a.ps) {
        for (auto p2 : b.ps) {
          res.push_back(p1 + p2);
        }
      }
    } else {
      auto MinYCmp = [](auto& a, auto& b) {
        if (abs(a.y - b.y) > Point::eps) return a.y < b.y;
        return a.x < b.x;
      };
      std::rotate(a.ps.begin(),
                  std::min_element(a.ps.begin(), a.ps.end(), MinYCmp),
                  a.ps.end());
      std::rotate(b.ps.begin(),
                  std::min_element(b.ps.begin(), b.ps.end(), MinYCmp),
                  b.ps.end());
      std::vector<Point> aa(n), bb(m);
      for (int i = 0; i < n; i++) {
        aa[i] = a.ps[(i + 1) % n] - a.ps[i];
      }
      for (int i = 0; i < m; i++) {
        bb[i] = b.ps[(i + 1) % m] - b.ps[i];
      }
      std::vector<Point> all;
      std::merge(aa.begin(), aa.end(), bb.begin(), bb.end(),
                 std::back_inserter(all),
                 [](auto& u, auto& v) { return u % v >= -Point::eps; });
      res.push_back(a.ps[0] + b.ps[0]);
      for (auto& u : all) {
        auto p = res.back() + u;
        res.push_back(p);
      }
      assert(Dist2(res[0], res.back()) <= Point::eps);
      res.pop_back();
    }
    return GetConvex(res);
  }
};

template <typename T>
struct TPoint {
  using type = T;
  using dim = std::integral_constant<int, 2>;
  static const T eps;

  T x, y;
  TPoint(T x_ = 0, T y_ = 0) : x(x_), y(y_) {}
  int Section() const {
    assert(abs(x) > eps || abs(y) > eps);
    if (x > 0 && y >= 0) return 1;
    if (x <= 0 && y > 0) return 2;
    if (x < 0 && y <= 0) return 3;
    if (x >= 0 && y < 0) return 4;
    assert(0);
  }
  template <typename Out = T>
  Out Length2() const {
    return (Out)x * x + (Out)y * y;
  }
  long double Length() const {
    return sqrt((long double)x * x + (long double)y * y);
  }
  template <typename Out = T>
  friend Out Dist2(const TPoint<T>& a, const TPoint<T>& b) {
    Out dx = a.x - b.x, dy = a.y - b.y;
    return dx * dx + dy * dy;
  }
  friend long double Dist(const TPoint<T>& a, const TPoint<T>& b) {
    long double dx = a.x - b.x, dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
  }
  TPoint<T> operator-() {
    auto res = *this;
    res.x = -res.x;
    res.y = -res.y;
    return res;
  }
  TPoint<T>& operator+=(const TPoint<T>& b) {
    x += b.x, y += b.y;
    return *this;
  }
  TPoint<T> operator+(const TPoint<T>& b) const {
    auto res = *this;
    return res += b;
  }
  TPoint<T>& operator-=(const TPoint<T>& b) {
    x -= b.x, y -= b.y;
    return *this;
  }
  TPoint<T> operator-(const TPoint<T>& b) const {
    auto res = *this;
    return res -= b;
  }
  TPoint<T>& operator*=(T t) {
    x *= t, y *= t;
    return *this;
  }
  TPoint<T> operator*(T t) const {
    auto res = *this;
    return res *= t;
  }
  friend TPoint<T> operator*(T t, const TPoint<T>& a) { return a * t; }
  TPoint<T>& operator/=(T t) {
    x /= t, y /= t;
    return *this;
  }
  TPoint<T> operator/(T t) const {
    auto res = *this;
    return res /= t;
  }
  T operator*(const TPoint<T>& b) const { return x * b.x + y * b.y; }
  T operator%(const TPoint<T>& b) const { return x * b.y - y * b.x; }
  bool operator|(const TPoint<T>& b) const { return abs((*this) % b) <= eps; }
  bool operator<(const TPoint<T>& b) const {
    if (x != b.x) return x < b.x;
    return y < b.y;
  }
  bool operator==(const TPoint<T>& b) const { return x == b.x && y == b.y; }
  operator std::string() const {
    if constexpr (std::is_convertible_v<T, std::string>) {
      return "Point(" + std::string(x) + ", " + std::string(y) + ")";
    } else {
      return "Point(" + std::to_string(x) + ", " + std::to_string(y) + ")";
    }
  }
  friend std::istream& operator>>(std::istream& input, TPoint<T>& a) {
    input >> a.x >> a.y;
    return input;
  }
  friend std::ostream& operator<<(std::ostream& output, const TPoint<T>& a) {
    output << static_cast<std::string>(a);
    return output;
  }
};

using point = TPoint<long double>;
template <>
const long double point::eps = 1e-12;
using geo = Geometry<point>;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n;
  cin >> n;
  vector<point> a;
  a.push_back({0, 0});
  long double ans = -2 * point::eps;
  for (int i = 0; i < n; i++) {
    point p;
    cin >> p.x >> p.y;
    if (i == 0) {
      a.push_back(p);
      continue;
    }
    debug(i, a);
    int l = 1, r = a.size() - 1, res = r;
    while (l <= r) {
      int mid = (l + r) / 2;
      if ((a[mid - 1] - a[mid]) % (p - a[mid]) < point::eps) {
        res = mid;
        r = mid - 1;
      } else {
        l = mid + 1;
      }
    }
    debug(res);
    geo::Line l1(point(0, 0), point(0, 1));
    geo::Line l2(p, a[res] - p);
    point q = geo::LineToLineIntersection(l1, l2);
    ans = max(ans, q.y);
    a.resize(res);
    a.push_back(p);
  }
  if (ans == -2 * point::eps) {
    cout << "-1\n";
  } else {
    cout << fixed << setprecision(10) << ans << '\n';
  }

  return 0;
}

Submission Info

Submission Time
Task F - Visible Buildings
User xindubawukong
Language C++ 20 (gcc 12.2)
Score 525
Code Size 14654 Byte
Status AC
Exec Time 59 ms
Memory 3816 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 525 / 525
Status
AC × 4
AC × 27
Set Name Test Cases
Sample sample_01.txt, sample_02.txt, sample_03.txt, sample_04.txt
All hand_01.txt, hand_02.txt, hand_03.txt, hand_04.txt, random_01.txt, random_02.txt, random_03.txt, random_04.txt, random_05.txt, random_06.txt, random_07.txt, random_08.txt, random_09.txt, random_10.txt, random_11.txt, random_12.txt, random_13.txt, random_14.txt, random_15.txt, random_16.txt, random_17.txt, random_18.txt, random_19.txt, sample_01.txt, sample_02.txt, sample_03.txt, sample_04.txt
Case Name Status Exec Time Memory
hand_01.txt AC 1 ms 3792 KiB
hand_02.txt AC 1 ms 3596 KiB
hand_03.txt AC 1 ms 3724 KiB
hand_04.txt AC 1 ms 3552 KiB
random_01.txt AC 59 ms 3728 KiB
random_02.txt AC 43 ms 3772 KiB
random_03.txt AC 38 ms 3720 KiB
random_04.txt AC 20 ms 3724 KiB
random_05.txt AC 42 ms 3812 KiB
random_06.txt AC 23 ms 3796 KiB
random_07.txt AC 8 ms 3712 KiB
random_08.txt AC 30 ms 3724 KiB
random_09.txt AC 5 ms 3728 KiB
random_10.txt AC 12 ms 3716 KiB
random_11.txt AC 35 ms 3752 KiB
random_12.txt AC 25 ms 3728 KiB
random_13.txt AC 6 ms 3780 KiB
random_14.txt AC 13 ms 3704 KiB
random_15.txt AC 44 ms 3728 KiB
random_16.txt AC 38 ms 3600 KiB
random_17.txt AC 27 ms 3780 KiB
random_18.txt AC 41 ms 3816 KiB
random_19.txt AC 31 ms 3728 KiB
sample_01.txt AC 1 ms 3804 KiB
sample_02.txt AC 1 ms 3632 KiB
sample_03.txt AC 1 ms 3708 KiB
sample_04.txt AC 1 ms 3680 KiB