QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#35595#972. CircleAutumnKiteWA 587ms4392kbC++1717.1kb2022-06-17 10:29:062022-06-17 10:29:07

Judging History

你现在查看的是最新测评结果

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2022-06-17 10:29:07]
  • 评测
  • 测评结果:WA
  • 用时:587ms
  • 内存:4392kb
  • [2022-06-17 10:29:06]
  • 提交

answer

#include <bits/stdc++.h>

template<typename Tp, typename Comp>
class geometry {
public:
  static constexpr Tp pi = 3.14159265358979324L;

  static int sgn(const Tp &a, const Tp &b = Tp()) {
    static Comp cmp;
    return cmp(a, b) ? -1 : (cmp(b, a) ? 1 : 0);
  }

  static Tp safe_sqrt(const Tp &a) {
    if (!sgn(a)) {
      return Tp();
    } else {
      return std::sqrt(a);
    }
  }

  struct point {
    Tp x, y;

    point() : x(), y() {}

    point(const Tp &t_x, const Tp &t_y) : x(t_x), y(t_y) {}

    Tp len2() const {
      return x * x + y * y;
    }

    Tp len() const {
      return safe_sqrt(len2());
    }

    point unit2() const {
      Tp l = len2();
      if (!sgn(l)) {
        return point();
      }
      return point(x / l, y / l);
    }

    point unit() const {
      Tp l = len();
      if (!sgn(l)) {
        return point();
      }
      return point(x / l, y / l);
    }

    Tp angle() const {
      Tp t = std::atan2(y, x);
      if (sgn(t) < 0) {
        t += 2 * pi;
      }
      return t;
    }

    point rotate(Tp th) const {
      return point(x * std::cos(th) - y * std::sin(th),
                   y * std::cos(th) + x * std::sin(th));
    }

    point rotate90() const {
      return point(-y, x);
    }

    point &operator+=(const point &rhs) {
      x += rhs.x, y += rhs.y;
      return *this;
    }

    point &operator-=(const point &rhs) {
      x -= rhs.x, y -= rhs.y;
      return *this;
    }

    point &operator*=(const Tp &rhs) {
      x *= rhs, y *= rhs;
      return *this;
    }

    point &operator/=(const Tp &rhs) {
      x /= rhs, y /= rhs;
      return *this;
    }

    bool sgn_equal(const point &rhs) const {
      return !sgn(x, rhs.x) && !sgn(y, rhs.y);
    }

    friend point operator+(const point &lhs, const point &rhs) {
      return point(lhs.x + rhs.x, lhs.y + rhs.y);
    }

    friend point operator-(const point &lhs, const point &rhs) {
      return point(lhs.x - rhs.x, lhs.y - rhs.y);
    }

    friend point operator*(const point &lhs, const Tp &rhs) {
      return point(lhs.x * rhs, lhs.y * rhs);
    }

    friend point operator*(const Tp &lhs, const point &rhs) {
      return point(lhs * rhs.x, lhs * rhs.y);
    }

    friend point operator/(const point &lhs, const Tp &rhs) {
      return point(lhs.x / rhs, lhs.y / rhs);
    }

    friend bool operator==(const point &lhs, const point &rhs) {
      return lhs.x == rhs.x && lhs.y == rhs.y;
    }

    friend bool operator<(const point &lhs, const point &rhs) {
      return lhs.x < rhs.x || (lhs.x == rhs.x && lhs.y < rhs.y);
    }

    friend std::istream &operator>>(std::istream &in, point &p) {
      return in >> p.x >> p.y;
    }

    friend std::ostream &operator<<(std::ostream &out, const point &p) {
      return out << p.x << " " << p.y;
    }
  };

  static Tp dot(const point &a, const point &b) {
    return a.x * b.x + a.y * b.y;
  }

  static Tp cross(const point &a, const point &b) {
    return a.x * b.y - a.y * b.x;
  }

  static Tp angle(const point &a, const point &b) {
    Tp t = std::atan2(cross(a, b), dot(a, b));
    if (sgn(t) < 0) {
      t += 2 * pi;
    }
    return t;
  }

  static Tp distance2(const point &a, const point &b) {
    return (a - b).len2();
  }

  static Tp distance(const point &a, const point &b) {
    return (a - b).len();
  }

  enum direction_t {
    COUNTER_CLOCKWISE,
    CLOCKWISE,
    ONLINE_BACK,
    ONLINE_FRONT,
    ON_SEGMENT
  };

  struct line {
    point a, b;

    line() : a(), b() {}

    line(const point &t_a, const point &t_b) : a(t_a), b(t_b) {}

    Tp get_Y(const Tp &X) const {
      if (sgn(a.x, b.x) == 0) {
        return a.y;
      }
      return (a + (X - a.x) / (b.x - a.x) * (b - a)).y;
    }

    line rev() const {
      return line(b, a);
    }

    direction_t direction(const point &p) const {
      int t = sgn(cross(b - a, p - a));
      if (t > 0) {
        return COUNTER_CLOCKWISE;
      }
      if (t < 0) {
        return CLOCKWISE;
      }
      Tp l1 = dot(p - a, b - a);
      if (sgn(l1) < 0) {
        return ONLINE_BACK;
      }
      Tp l2 = dot(b - a, b - a);
      if (sgn(l1, l2) > 0) {
        return ONLINE_FRONT;
      }
      return ON_SEGMENT;
    }

    point midpoint() const {
      return (a + b) / 2;
    }

    line vertical_bisector() const {
      point p = midpoint();
      return line(p, p + (b - p).rotate90());
    }
  };

  static bool parallel(const line &a, const line &b) {
    return !sgn(cross(a.b - a.a, b.b - b.a));
  }

  static point projection(const line &l, const point &p) {
    return l.a + (l.b - l.a).unit2() * dot(p - l.a, l.b - l.a);
  }

  static std::vector<point> line_cross(const line &a, const line &b) {
    if (parallel(a, b)) {
      return {};
    }
    point u = a.a - b.a, v = a.b - a.a, w = b.b - b.a;
    return {a.a + cross(w, u) / cross(v, w) * v};
  }

  static std::vector<point> segment_cross(const line &a, const line &b) {
    Tp t1 = cross(b.a - a.a, a.b - a.a), t2 = cross(b.b - a.a, a.b - a.a);
    Tp t3 = cross(a.a - b.a, b.b - b.a), t4 = cross(a.b - b.a, b.b - b.a);
    if (!sgn(t1) && !sgn(t2) && !sgn(t3) && !sgn(t4)) {
      if (sgn(std::min(a.a.x, a.b.x), std::max(b.a.x, b.b.x)) > 0) {
        return {};
      }
      if (sgn(std::min(b.a.x, b.b.x), std::max(a.a.x, a.b.x)) > 0) {
        return {};
      }
      if (sgn(std::min(a.a.y, a.b.y), std::max(b.a.y, b.b.y)) > 0) {
        return {};
      }
      if (sgn(std::min(b.a.y, b.b.y), std::max(a.a.y, a.b.y)) > 0) {
        return {};
      }
      return {std::max(std::min(a.a, a.b), std::min(b.a, b.b)),
              std::min(std::max(a.a, a.b), std::max(b.a, b.b))};
    }
    if (sgn(t1) * sgn(t2) > 0) {
      return {};
    }
    if (sgn(t3) * sgn(t4) > 0) {
      return {};
    }
    return line_cross(a, b);
  }

  static std::vector<point> segment_set_cross(const std::vector<line> &s) {
    using pointer = typename std::vector<line>::const_iterator;

    std::vector<std::tuple<Tp, bool, pointer>> op;
    for (pointer it = s.begin(); it != s.end(); ++it) {
      if (sgn(it->a.x, it->b.x) > 0) {
        op.emplace_back(it->a.x, true, it);
        op.emplace_back(it->b.x, false, it);
      } else {
        op.emplace_back(it->a.x, false, it);
        op.emplace_back(it->b.x, true, it);
      }
    }
    std::sort(op.begin(), op.end(), [&](const auto &a, const auto &b) {
      int t = sgn(std::get<0>(a), std::get<0>(b));
      if (t) {
        return t < 0;
      }
      return std::make_pair(std::get<1>(a), std::get<2>(a)) <
             std::make_pair(std::get<1>(b), std::get<2>(b));
    });

    Tp now = 0;

    std::function<bool(pointer, pointer)> cmp = [&](pointer i, pointer j) {
      int t = sgn(i->get_Y(now), j->get_Y(now));
      if (t) {
        return t < 0;
      }
      return i < j;
    };

    std::set<pointer, decltype(cmp)> S(cmp);
    bool ok = false;
    point ans;

    auto upd = [&](pointer i, pointer j) {
      auto tmp = segment_cross(*i, *j);
      if (!tmp.empty()) {
        if (!ok) {
          ok = true;
          ans = *tmp.begin();
        } else {
          ans = std::min(ans, *tmp.begin());
        }
      }
      return tmp;
    };

    for (auto p : op) {
      now = std::get<0>(p);
      if (ok && sgn(ans.x, now) < 0) {
        break;
      }
      pointer it = std::get<2>(p);
      if (std::get<1>(p)) {
        S.erase(it);
        auto nx = S.upper_bound(it);
        if (nx != S.begin() && nx != S.end()) {
          upd(*std::prev(nx), *nx);
        }
      } else {
        auto nx = S.upper_bound(it);
        if (nx != S.end()) {
          upd(it, *nx);
        }
        if (nx != S.begin()) {
          upd(*std::prev(nx), it);
        }
        S.insert(it);
      }
    }
    if (ok) {
      return {ans};
    } else {
      return {};
    }
  }

  using polygon = std::vector<point>;

  static polygon convex_hull(std::vector<point> f) {
    if (f.empty()) {
      return polygon();
    }
    std::size_t t = 0;
    for (std::size_t i = 1; i < f.size(); ++i) {
      if (f[i].y < f[t].y || (f[i].y == f[t].y && f[i].x < f[t].x)) {
        t = i;
      }
    }
    std::rotate(f.begin(), f.begin() + t, f.end());
    std::sort(f.begin() + 1, f.end(), [&](const point &p, const point &q) {
      int tmp = sgn(cross(p - f[0], q - f[0]));
      if (tmp) {
        return tmp > 0;
      }
      return distance(p, f[0]) < distance(q, f[0]);
    });
    polygon p;
    for (std::size_t i = 0; i < f.size(); ++i) {
      while (p.size() > 1 &&
             cross(f[i] - p.back(), p[p.size() - 2] - p.back()) <= 0) {
        p.pop_back();
      }
      p.push_back(f[i]);
    }
    return p;
  }

  static polygon convex_cut(const polygon &g, const line &l) {
    polygon res;
    for (std::size_t i = 0; i < g.size(); ++i){
      point u = g[i], v = g[(i + 1) % g.size()];
      if (sgn(cross(l.b - l.a, u - l.a)) >= 0) {
        res.push_back(u);
        if (sgn(cross(l.b - l.a, v - l.a)) < 0) {
          res.push_back(line_cross(line(u, v), l)[0]);
        }
      } else if (sgn(cross(l.b - l.a, v - l.a)) > 0) {
        res.push_back(line_cross(line(u, v), l)[0]);
      }
    }
    return res;
  }

  static Tp polygon_directed_area(const polygon &g) {
    Tp s = 0;
    for (std::size_t i = 0; i < g.size(); ++i) {
      s += cross(g[i], g[(i + 1) % g.size()]);
    }
    return s / 2;
  }

  static polygon half_plane_intersection(const std::vector<line> &ls,
                                         const point &min, const point &max) {
    std::vector<std::pair<Tp, line>> f;
    for (const auto &l : ls) {
      f.emplace_back(0, l);
    }
		f.emplace_back(0, line(point(min.x, min.y), point(max.x, min.y)));
		f.emplace_back(0, line(point(max.x, min.y), point(max.x, max.y)));
		f.emplace_back(0, line(point(max.x, max.y), point(min.x, max.y)));
		f.emplace_back(0, line(point(min.x, max.y), point(min.x, min.y)));
    for (auto &p : f) {
      p.first = (p.second.b - p.second.a).angle();
    }
    std::sort(f.begin(), f.end(), [&](const auto &a, const auto &b) {
      int t = sgn(a.first, b.first);
      if (t) {
        return t < 0;
      }
      return a.second.direction(b.second.a) == CLOCKWISE;
    });
    std::deque<line> Ql;
    std::deque<point> Qp;
    Ql.push_back(f[0].second);
    for (std::size_t i = 1; i < f.size(); ++i) {
      if (sgn(f[i - 1].first, f[i].first)) {
        while (!Qp.empty() && f[i].second.direction(Qp.back()) == CLOCKWISE) {
          Qp.pop_back();
          Ql.pop_back();
        }
        while (!Qp.empty() && f[i].second.direction(Qp.front()) == CLOCKWISE) {
          Qp.pop_front();
          Ql.pop_front();
        }
        auto tmp = line_cross(Ql.back(), f[i].second);
        if (tmp.empty()) {
          return polygon();
        }
        Qp.push_back(tmp[0]);
        Ql.push_back(f[i].second);
      }
    }
    while (!Qp.empty() && Ql.front().direction(Qp.back())) {
      Qp.pop_back();
      Ql.pop_back();
    }
    if (Ql.size() < 3) {
      return polygon();
    }
    auto tmp = line_cross(Ql.back(), Ql.front());
    if (tmp.empty()) {
      return polygon();
    }
    Qp.push_back(tmp[0]);
    return polygon(Qp.begin(), Qp.end());
  }

  static std::vector<std::size_t> half_plane_intersection_id(
      const std::vector<line> &ls, const point &min, const point &max) {
    std::vector<std::pair<std::pair<Tp, std::size_t>, line>> f;
    for (std::size_t i = 0; i < ls.size(); ++i) {
      f.emplace_back(std::pair<Tp, std::size_t>(0, i), ls[i]);
    }
    std::pair<Tp, std::size_t> add(0, -1);
		f.emplace_back(add, line(point(min.x, min.y), point(max.x, min.y)));
		f.emplace_back(add, line(point(max.x, min.y), point(max.x, max.y)));
		f.emplace_back(add, line(point(max.x, max.y), point(min.x, max.y)));
		f.emplace_back(add, line(point(min.x, max.y), point(min.x, min.y)));
    for (auto &p : f) {
      p.first.first = (p.second.b - p.second.a).angle();
    }
    std::sort(f.begin(), f.end(), [&](const auto &a, const auto &b) {
      int t = sgn(a.first.first, b.first.first);
      if (t) {
        return t < 0;
      }
      return a.second.direction(b.second.a) == CLOCKWISE;
    });
    std::deque<std::pair<std::size_t, line>> Ql;
    std::deque<point> Qp;
    Ql.emplace_back(f[0].first.second, f[0].second);
    for (std::size_t i = 1; i < f.size(); ++i) {
      if (sgn(f[i - 1].first.first, f[i].first.first)) {
        while (!Qp.empty() && f[i].second.direction(Qp.back()) == CLOCKWISE) {
          Qp.pop_back();
          Ql.pop_back();
        }
        while (!Qp.empty() && f[i].second.direction(Qp.front()) == CLOCKWISE) {
          Qp.pop_front();
          Ql.pop_front();
        }
        auto tmp = line_cross(Ql.back().second, f[i].second);
        if (tmp.empty()) {
          return std::vector<std::size_t>();
        }
        Qp.push_back(tmp[0]);
        Ql.emplace_back(f[i].first.second, f[i].second);
      }
    }
    while (!Qp.empty() && Ql.front().second.direction(Qp.back())) {
      Qp.pop_back();
      Ql.pop_back();
    }
    if (Ql.size() < 3) {
      return std::vector<std::size_t>();
    }
    auto tmp = line_cross(Ql.back().second, Ql.front().second);
    if (tmp.empty()) {
      return std::vector<std::size_t>();
    }
    Qp.push_back(tmp[0]);
    std::vector<std::size_t> res;
    for (const auto &p : Ql) {
      if (p.first != add.second) {
        res.push_back(p.first);
      }
    }
    return res;
  }

  struct circle {
    point o;
    Tp r;

    circle() : o(), r() {}

    circle(const point &t_o, const Tp &t_r) : o(t_o), r(t_r) {}
  };

  static int circle_point_relation(const circle &a, const point &p) {
    return sgn(distance2(a.o, p), a.r * a.r);
  }

  static std::vector<point> circle_cross(const circle &a, const circle &b) {
    Tp d = distance(a.o, b.o);
    if (sgn(d, a.r + b.r) > 0 || sgn(d, std::abs(a.r - b.r)) < 0 || !sgn(d)) {
      return {};
    }
    Tp x = (a.r * a.r - b.r * b.r + d * d) / (d * 2);
    Tp h = safe_sqrt(a.r * a.r - x * x);
    point p = a.o + x * (b.o - a.o).unit();
    point v = h * (b.o - a.o).unit().rotate90();
    if (!sgn(v.x) && !sgn(v.y)) {
      return {p};
    } else {
      return {p - v, p + v};
    }
  }

  static std::vector<point> circle_tangent(const circle &a, const point &p) {
    Tp d = distance(a.o, p);
    int t = sgn(d, a.r);
    if (t < 0) {
      return {};
    } else if (t == 0) {
      return {p};
    } else {
      return circle_cross(circle(p, safe_sqrt(d * d - a.r * a.r)), a);
    }
  }

  static std::vector<point> circle_common_tangent_out(const circle &a,
                                                      const circle &b) {
    if (!sgn(a.r, b.r)) {
      point p = (a.o - b.o).unit().rotate90() * a.r;
      return {a.o - p, a.o + p};
    }
    point p = (a.o * b.r - b.o * a.r) / (b.r - a.r);
    return circle_tangent(a, p);
  }

  static std::vector<point> circle_line_cross(const circle &c, const line &l) {
    point p = projection(line(l.a, l.b), c.o), v = (l.b - l.a).unit();
    Tp d = distance(p, c.o);
    if (sgn(d, c.r) > 0) {
      return {};
    }
    Tp t = sqrt(c.r * c.r - (p - c.o).len2());
    if (!sgn(t)) {
      return {p};
    } else {
      return {p - v * t, p + v * t};
    }
  }
};

struct double_compare {
  constexpr bool operator()(const double &a, const double &b) const {
    return a + 1e-9 <= b;
  }
};

using geo = geometry<double, double_compare>;

int main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr);
  
  std::cout.setf(std::ios::fixed);
  std::cout.precision(3);

  int T;
  std::cin >> T;
  while (T--) {
    geo::point A, B;
    geo::circle C;
    std::cin >> A >> B >> C.o >> C.r;
    auto pA = geo::circle_tangent(C, A);
    auto pB = geo::circle_tangent(C, B);
    if (pA.size() == 1) {
      pA.push_back(pA[0]);
    }
    if (pB.size() == 1) {
      pB.push_back(pB[0]);
    }
    if (!geo::circle_line_cross(C, geo::line(A, B)).empty()) {
      double s0 = geo::distance(A, pA[0]) + geo::distance(B, pB[1]) +
                  geo::angle(pA[0] - C.o, pB[1] - C.o) * C.r;
      double s1 = geo::distance(B, pB[0]) + geo::distance(A, pA[1]) +
                  geo::angle(pB[0] - C.o, pA[1] - C.o) * C.r;
      std::cout << std::min(s0, s1) << "\n";
      continue;
    }
    double l, r;
    if (geo::sgn(geo::cross(pB[1] - C.o, pA[0] - C.o)) > 0) {
      l = (pB[1] - C.o).angle();
      r = (pA[0] - C.o).angle();
    } else {
      l = (pA[1] - C.o).angle();
      r = (pB[0] - C.o).angle();
    }
    if (geo::sgn(r, l) < 0) {
      r += 2 * geo::pi;
    }

    auto calc = [&](double x) {
      auto P = C.o + geo::point(C.r, 0).rotate(x);
      return geo::distance(A, P) + geo::distance(B, P);
    };

    for (int i = 0; i < 60; ++i) {
      double mid = (l + r) / 2;
      if (calc(mid) > calc(mid + 1e-6)) {
        l = mid;
      } else {
        r = mid;
      }
    }
    std::cout << calc(l) << "\n";
  }
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 2ms
memory: 4268kb

input:

3
0 0 2 2 1 1 1
0 0 2 2 1 0 1
0 0 2 2 1 -1 1

output:

3.571
2.927
3.116

result:

ok 3 tokens

Test #2:

score: -100
Wrong Answer
time: 587ms
memory: 4392kb

input:

100000
-9 -2 10 -3 -5 1 1
-7 0 -5 5 4 -8 10
6 -7 -2 -4 0 10 1
-5 -4 9 3 2 -10 9
10 3 1 -10 -10 -5 7
0 4 4 -1 2 6 2
-8 -10 4 -2 -1 4 3
2 8 4 10 -4 -9 4
8 0 -4 -10 8 -2 1
8 -4 -2 9 2 -3 3
-10 6 -4 1 6 2 8
-6 -7 -10 -4 1 -6 7
4 9 -1 9 -1 4 5
0 -7 4 1 10 -3 7
5 4 1 6 8 -6 1
7 8 -3 -9 -7 -1 5
-5 -2 -8 9 ...

output:

19.764
10.267
30.231
15.704
21.568
7.086
18.779
30.648
15.732
16.598
54.298
44.195
5.000
8.957
22.348
20.509
11.755
12.130
25.936
18.512
26.847
17.582
22.441
19.312
27.234
23.249
27.692
48.343
32.276
20.463
11.735
5.657
43.987
28.328
11.520
10.298
14.765
26.516
23.500
23.901
29.973
23.523
15.324
31....

result:

wrong answer 11th words differ - expected: '11.180', found: '54.298'