QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#871528#8620. Jigsaw Puzzleucup-team4435#ML 0ms4224kbC++2030.8kb2025-01-25 20:59:362025-01-25 20:59:44

Judging History

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

  • [2025-01-25 20:59:44]
  • 评测
  • 测评结果:ML
  • 用时:0ms
  • 内存:4224kb
  • [2025-01-25 20:59:36]
  • 提交

answer

#pragma GCC optimize("Ofast")

#include "bits/stdc++.h"


#define rep(i, n) for (int i = 0; i < (n); ++i)
#define rep1(i, n) for (int i = 1; i < (n); ++i)
#define rep1n(i, n) for (int i = 1; i <= (n); ++i)
#define repr(i, n) for (int i = (n) - 1; i >= 0; --i)
//#define pb push_back
#define eb emplace_back
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define each(x, a) for (auto &x : a)
#define ar array
#define vec vector
#define range(i, n) rep(i, n)

using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using str = string;
using pi = pair<int, int>;
using pl = pair<ll, ll>;

using vi = vector<int>;
using vl = vector<ll>;
using vpi = vector<pair<int, int>>;
using vvi = vector<vi>;

int Bit(int mask, int b) { return (mask >> b) & 1; }

template<class T>
bool ckmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool ckmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return true;
    }
    return false;
}

// [l, r)
template<typename T, typename F>
T FindFirstTrue(T l, T r, const F &predicat) {
    --l;
    while (r - l > 1) {
        T mid = l + (r - l) / 2;
        if (predicat(mid)) {
            r = mid;
        } else {
            l = mid;
        }
    }
    return r;
}


template<typename T, typename F>
T FindLastFalse(T l, T r, const F &predicat) {
    return FindFirstTrue(l, r, predicat) - 1;
}

const int INFi = 2e9;
const ll INF = 2e18;

bool Equal(ll A, ll B) {
    return A == B;
}

bool Less(ll A, ll B) {
    return A < B;
}

bool Greater(ll A, ll B) {
    return A > B;
}

bool LessOrEqual(ll A, ll B) {
    return A <= B;
}

bool GreaterOrEqual(ll A, ll B) {
    return A >= B;
}

const ld EPS = 1e-9;

bool Equal(ld A, ld B) {
    return abs(A - B) < EPS;
}

bool Less(ld A, ld B) {
    return A + EPS < B;
}

bool Greater(ld A, ld B) {
    return A > B + EPS;
}

bool LessOrEqual(ld A, ld B) {
    return A <= B + EPS;
}

bool GreaterOrEqual(ld A, ld B) {
    return A + EPS >= B;
}

template<typename T, typename Q>
bool LessOrEqual(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return LessOrEqual(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool Equal(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return Equal(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool Less(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return Less(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool Greater(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return Greater(static_cast<C>(A), static_cast<C>(B));
}

template<typename T, typename Q>
bool GreaterOrEqual(T A, Q B) {
    using C = std::common_type_t<T, Q>;
    return GreaterOrEqual(static_cast<C>(A), static_cast<C>(B));
}

template<typename T>
ll sgn(T x) {
    if (Equal(x, 0)) return 0;
    return Less(x, 0) ? -1 : 1;
}


template<typename T>
struct Point {
    T x;
    T y;

    Point(T x_ = 0, T y_ = 0) : x(x_), y(y_) {}

    template<typename Q>
    Point(const Point<Q> &other) {
        x = static_cast<T>(other.x);
        y = static_cast<T>(other.y);
    }


    template<typename Q>
    Point(Point<Q> &&other) {
        x = static_cast<T>(other.x);
        y = static_cast<T>(other.y);
    }

    template<typename Q>
    Point<std::common_type_t<T, Q>> operator+(const Point<Q> &oth) const {
        return Point{x + oth.x, y + oth.y};
    }

    template<typename Q>
    Point<std::common_type_t<T, Q>> operator-(const Point<Q> &oth) const {
        return {x - oth.x, y - oth.y};
    }

    template<typename Q>
    bool operator==(const Point<Q> &oth) const {
        return x == oth.x && y == oth.y;
    }

    template<typename Q>
    bool operator<(const Point<Q> &oth) const {
        return make_pair(x, y) < make_pair(oth.x, oth.y);
    }

    template<typename Q>
    requires (is_integral_v<Q> || is_floating_point_v<Q>)
    Point<std::common_type_t<Q, T>> operator*(const Q &b) const {
        return {x * b, y * b};
    }


    template<typename Q>
    requires (is_integral_v<Q> || is_floating_point_v<Q>)
    Point<ld> operator/(const Q &b) const {
        return {(ld) x / b, (ld) y / b};
    }

    template<typename Q>
    std::common_type_t<Q, T> operator*(const Point<Q> &oth) const {
        return x * oth.y - y * oth.x;
    }

    template<typename Q>
    std::common_type_t<Q, T> operator%(const Point<Q> &oth) const {
        return x * oth.x + y * oth.y;
    }

    Point &operator+=(const Point &other) {
        x += other.x;
        y += other.y;
        return *this;
    }

    Point &operator-=(const Point &other) {
        x -= other.x;
        y -= other.y;
        return *this;
    }

    friend ostream &operator<<(ostream &stream, const Point &P) {
        stream << P.x << ' ' << P.y;
        return stream;
    }


    friend istream &operator>>(istream &stream, Point &P) {
        stream >> P.x >> P.y;
        return stream;
    }
};

template<typename T>
Point<T> rotateCW(const Point<T> &P) {
    return {P.y, -P.x};
}

template<typename T>
Point<T> rotateCCW(const Point<T> &P) {
    return {-P.y, P.x};
}

template<typename T, typename Q>
bool Equal(const Point<T> &a, const Point<Q> &b) {
    return Equal(a.x, b.x) && Equal(a.y, b.y);
}

template<typename T, typename Q>
bool Less(const Point<T> &a, const Point<Q> &b) {
    if (!Equal(a.x, b.x)) return Less(a.y, b.y);
    return Less(a.y, b.y);
}

template<typename T, typename Q>
bool Greater(const Point<T> &a, const Point<Q> &b) {
    if (!Equal(a.x, b.x)) return Greater(a.y, b.y);
    return Greater(a.y, b.y);
}

template<typename T>
Point<T> operator-(const Point<T> &a) {
    return {-a.x, -a.y};
}


template<typename T>
T len2(const Point<T> &a) {
    return a % a;
}

template<typename T>
ld len(const Point<T> &a) {
    return sqrtl(len2(a));
}

template<typename T, typename Q>
T dist2(const Point<T> &a, const Point<Q> &b) {
    return len2(a - b);
}

template<typename T, typename Q>
ld dist(const Point<T> &a, const Point<Q> &b) {
    return len(a - b);
}

using pt = Point<ll>;
using ptd = Point<ld>;

template<typename T = ld>
const Point<T> NULL_POINT = {T(-INFi - 1337), T(INFi + 228)};

template<typename T>
struct Segment;

template<typename T>
struct Ray;

template<typename T>
struct Line {
    T a, b, c;
    // ax + by = c


    template<class Q>
    Line(const Line<Q> &other) {
        a = other.a;
        b = other.b;
        c = other.c;
    }

    Line(const Point<T> &F, Point<T> V, bool isDirection = false) {
        if (!isDirection) {
            V -= F;
        }
        a = V.y;
        b = -V.x;
        c = a * F.x + b * F.y;
    }


    Line(const T &a1 = 0, const T &b1 = 0, const T &c1 = 0) {
        a = a1;
        b = b1;
        c = c1;
    }

    template<class Q>
    explicit Line(const Segment<Q> &other) : Line(other.A, other.B, false) {
    }

    template<class Q>
    explicit Line(const Ray<Q> &other) : Line(other.A, other.V, true) {
    }

    pair<ptd, ptd> GetPointAndDirection() const {
        ptd V = {-b, a};
        ptd A;
        if (!Equal(a, 0)) {
            A.y = 0;
            A.x = c / (ld) a;
        } else if (!Equal(b, 0)) {
            A.x = 0;
            A.y = c / (ld) b;
        } else {
            assert(0);
        }
        return {A, V};
    }

    template<class Q>
    ptd Proj(const Point<Q> &P) const {
        auto [A, V] = GetPointAndDirection();
        ld value = (P - A) % V;
        value /= (ld) len2(V);
        return ptd(A) + (ptd(V) * value);
    }

    template<class Q>
    bool Contains(const Point<Q> &P) const {
        return Equal(GetValue(P), c);
    }

    template<typename Q>
    ld Dist(const Point<Q> &P) const {
        return dist(Proj(P), P);
    }

    template<typename Q>
    std::common_type_t<Q, T> GetValue(const Point<Q> &P) const {
        return a * P.x + b * P.y;
    }

    friend ostream &operator<<(ostream &stream, const Line &L) {
        stream << L.a << ' ' << L.b << ' ' << L.c;
        return stream;
    }


    friend istream &operator>>(istream &stream, Line &L) {
        stream >> L.a >> L.b >> L.c;
        return stream;
    }
};


template<typename Q, typename U>
ld Dist(const Point<Q> &A, const Line<U> &line) {
    return line.Dist(A);
}

template<typename Q, typename U>
Point<ld> Intersect(const Line<Q> &line1, const Line<U> &line2) {
    using C = std::common_type_t<Q, U>;
    C det = line1.a * line2.b - line1.b * line2.a;
    if (Equal(det, 0)) return NULL_POINT<ld>;
    C detx = line1.c * line2.b - line1.b * line2.c;
    C dety = line1.a * line2.c - line1.c * line2.a;
    return {(ld) detx / (ld) det, (ld) dety / (ld) det};
}

template<typename Q, typename U>
bool IsParallel(const Line<Q> &line1, const Line<U> &line2) {
    return Equal(line1.a * line2.b - line1.b * line2.a, 0);
}

template<typename Q, typename U>
ld Dist(const Line<Q> &line1, const Line<U> &line2) {
    if (IsParallel(line1, line2)) {
        return line1.Dist(line2.A);
    }
    return 0;
}


template<typename T, typename U, typename V>
bool IsCollinear(const Point<T> &a, const Point<U> &b, const Point<V> &c) {
    return Equal((c - a) * (b - a), 0);
}

template<typename T, typename U, typename V>
bool IsInside(T L, U R, V P) {
    return LessOrEqual(L, P) && LessOrEqual(P, R);
}

template<typename T>
struct Segment {
    Point<T> A, B;

    Segment(const Point<T> &a = {0, 0}, const Point<T> &b = {0, 0}) : A(a), B(b) {
    }


    template<class Q>
    Segment(const Segment<Q> &other) : A(other.A), B(other.B) {
    }

    T len2() const {
        return dist2(A, B);
    }

    ld len() const {
        return dist(A, B);
    }

    template<class Q>
    bool Contains(const Point<Q> &P) const {
        if (!IsCollinear(A, B, P)) {
            return false;
        }
        return IsInside(min(A.x, B.x), max(A.x, B.x), P.x) && IsInside(min(A.y, B.y), max(A.y, B.y), P.y);
    }

    template<typename Q>
    ld Dist(const Point<Q> &P) const {
        ld answer = min(dist(P, A), dist(P, B));
        ptd Ap = Line<ld>(*this).Proj(P);
        if (Contains(Ap)) {
            answer = dist(Ap, P);
        }
        return answer;
    }
};


template<typename Q, typename U>
ld Dist(const Point<Q> A, const Segment<U> &seg) {
    return seg.Dist(A);
}


template<typename U, typename V>
bool isIntersected(const Segment<U> &seg1, const Segment<V> &seg2) {
    ll s1 = sgn((seg1.B - seg1.A) * (seg2.A - seg1.A)) * sgn((seg1.B - seg1.A) * (seg2.B - seg1.A));
    if (s1 > 0) return false;
    ll s2 = sgn((seg2.B - seg2.A) * (seg1.A - seg2.A)) * sgn((seg2.B - seg2.A) * (seg1.B - seg2.A));
    if (s2 > 0) return false;
    return s1 < 0 || s2 < 0 || seg1.Contains(seg2.A) || seg1.Contains(seg2.B) || seg2.Contains(seg1.A);
}

template<typename U, typename V>
ld Dist(const Segment<U> &seg1, const Segment<V> &seg2) {
    if (isIntersected(seg1, seg2)) {
        return 0;
    }
    return min(min(seg1.Dist(seg2.A), seg1.Dist(seg2.B)), min(seg2.Dist(seg1.A), seg2.Dist(seg1.B)));
}

template<typename U, typename V>
bool isIntersected(const Segment<U> &seg, const Line<V> &line) {
    return sgn((seg.A - line.A) * line.V) * sgn((seg.B - line.A) * line.V) <= 0;
}

template<typename Q, typename U>
ld Dist(const Segment<Q> &seg, const Line<U> &line) {
    if (isIntersected(seg, line)) {
        return 0;
    }
    return min(line.Dist(seg.A), line.Dist(seg.B));
}

template<typename T>
struct Ray {
    Point<T> A, V;

    Ray(const Point<T> &a = {0, 0}, const Point<T> &v = {1, 0}, bool isDirection = false) {
        if (isDirection) {
            A = a;
            V = v;
        } else {
            A = a;
            V = v - a;
        }
    }

    template<class Q>
    Ray(const Ray<Q> &other) : A(other.A), V(other.V) {
    }

    template<class Q>
    Ray(const Segment<Q> &other) : A(other.A), V(other.B - other.A) {
    }

    template<class Q>
    bool Contains(const Point<Q> &P) const {
        return Equal(V * (P - A), 0) && GreaterOrEqual(V % (P - A), 0);
    }

    template<typename Q>
    ld Dist(const Point<Q> &P) const {
        ld answer = dist(P, A);
        ptd Ap = Line<ld>(*this).Proj(P);
        if (Contains(Ap)) {
            answer = dist(Ap, P);
        }
        return answer;
    }
};


template<typename Q, typename U>
ld Dist(const Point<Q> A, const Ray<U> &ray) {
    return ray.Dist(A);
}


template<typename U, typename V>
bool isIntersected(const Segment<U> &seg, const Ray<V> &ray) {
    ll sA = sgn((seg.A - ray.A) * ray.V);
    ll sB = sgn((seg.B - ray.A) * ray.V);
    if (sA * sB > 0) return false;
    if (sA == 0 || sB == 0) return ray.Contains(seg.A) || ray.Contains(seg.B);
    ll sAB = sgn((seg.A - ray.A) * (seg.B - ray.A));
    return sAB == 0 || sAB == sA;
}


template<typename U, typename V>
ld Dist(const Segment<U> &seg, const Ray<V> &ray) {
    if (isIntersected(seg, ray)) {
        return 0;
    }
    return min(min(ray.Dist(seg.A), ray.Dist(seg.B)), seg.Dist(ray.A));
}


template<typename U, typename V>
bool isIntersected(const Ray<U> &ray1, const Ray<V> &ray2) {
    auto mid = Intersect(Line<U>(ray1), Line<V>(ray2));
    if (ray1.Contains(mid) && ray2.Contains(mid)) return true;
    return ray1.Contains(ray2.A) || ray2.Contains(ray1.A);
}

template<typename U, typename V>
ld Dist(const Ray<U> &ray1, const Ray<V> &ray2) {
    if (isIntersected(ray1, ray2)) {
        return 0;
    }
    return min(ray1.Dist(ray2.A), ray2.Dist(ray1.A));
}

template<typename U, typename V>
bool isIntersected(const Ray<U> &ray, const Line<V> &line) {
    auto mid = Intersect(Line<U>(ray), line);
    if (ray.Contains(mid)) return true;
    return line.Contains(ray.A);
}

template<typename U, typename V>
ld Dist(const Ray<U> &ray, const Line<V> &line) {
    if (isIntersected(ray, line)) {
        return 0;
    }
    return line.Dist(ray.A);
}

const ld PI = atan2(0, -1);

template<typename T = ld>
struct Circle {
    Point<T> O;
    T R;

    Circle(const Point<T> &o = {0, 0}, const T &r = 0) : O(o), R(r) {}

    template<typename Q>
    Circle(const Circle<Q> &other) : O(other.O), R(other.R) {}

    template<typename Q>
    Circle(Circle<Q> &&other) : O(other.O), R(other.R) {}

    ld Area() const {
        return R * R * PI;
    }


    template<typename U, typename V>
    Point<ld> GetCircleCenterWithZero(const Point<U> &b,
                                      const Point<V> &c) {
        ld B = len2(b);
        ld C = len2(c);
        ld D = b * c;
        return {(c.y * B - b.y * C) / (2 * D),
                (b.x * C - c.x * B) / (2 * D)};
    }

    template<typename U, typename V, typename W>
    Circle(const Point<U> &A, const Point<V> &B,
           const Point<W> &C) {
        static_assert(std::is_same_v<T, ld>);
        O = GetCircleCenterWithZero(B - A, C - A);
        R = len(O);
        O += A;
    }

    template<typename U, typename V>
    Circle(const Point<U> &A, const Point<V> &B) {
        static_assert(std::is_same_v<T, ld>);
        O = (A + B) / (ld) 2;
        R = (ld) dist(A, B) / (ld) 2;
    }

    template<typename U>
    bool isInside(const Point<U> &P) const {
        return LessOrEqual(dist(P, O), R);
    }
};

// return (L, R) points in counter-clock-wise order related circle1
// if no intersect or coincide return (NULL_POINT, NULL_POINT)
template<typename T, typename U>
pair<Point<ld>, Point<ld>> Intersect(const Circle<T> &circle1, const Circle<U> &circle2) {
    if (Equal(circle1.O, circle2.O) && Equal(circle2.R, circle1.R)) return {NULL_POINT<ld>, NULL_POINT<ld>};
    auto d2 = dist2(circle2.O, circle1.O);
    if (Equal(d2, 0)) return {NULL_POINT<ld>, NULL_POINT<ld>};
    if (Less((circle1.R + circle2.R) * (circle2.R + circle1.R), d2) ||
        Less(d2, (circle1.R - circle2.R) * (circle1.R - circle2.R)))
        return {NULL_POINT<ld>, NULL_POINT<ld>};
    ld d = sqrtl(d2);
    ld A = (d2 - circle2.R * circle2.R + circle1.R * circle1.R) / (2 * d);
    ld B = sqrtl(max((ld) 0, circle1.R * circle1.R - A * A));
    Point<ld> V = (circle2.O - circle1.O) / d;
    Point<ld> M = circle1.O + V * A;
    V = rotateCCW(V) * B;
    return {M - V, M + V};
}

template<typename T, typename U>
pair<Point<ld>, Point<ld>> Intersect(const Circle<T> &circle, const Line<U> &line) {
    auto [a, b] = line.GetPointAndDirection();
    a -= circle.O;
    auto A = len2(b);
    auto B = a % b;
    auto C = len2(a) - circle.R * circle.R;
    auto D = B * B - A * C;
    if (Less(D, 0)) return {NULL_POINT<ld>, NULL_POINT<ld>};
    if (D < 0) D = 0;
    Point<ld> result = circle.O + a;
    return {result + b * (-B + sqrtl(D)) / (ld) A,
            result + b * (-B - sqrtl(D)) / (ld) A};
}

template<typename U, typename V>
ld IntersectionArea(const Circle<U> &circle1, const Circle<V> &circle2) {
    ld d = dist(circle1.O, circle2.O);
    if (GreaterOrEqual(d, circle1.R + circle2.R)) {
        return 0;
    }
    if (LessOrEqual(d + circle1.R, circle2.R)) {
        return circle1.Area();
    }
    if (LessOrEqual(d + circle2.R, circle1.R)) {
        return circle2.Area();
    }
    ld alpha = acos((circle1.R * circle1.R + d * d - circle2.R * circle2.R) / (2 * circle1.R * d)) * 2;
    ld beta = acos((circle2.R * circle2.R + d * d - circle1.R * circle1.R) / (2 * circle2.R * d)) * 2;
    return 0.5 * circle2.R * circle2.R * (beta - sin(beta)) +
           0.5 * circle1.R * circle1.R * (alpha - sin(alpha));
}


template<typename U, typename V>
ld UnionArea(const Circle<U> &circle1, const Circle<V> &circle2) {
    return circle1.Area() + circle2.Area() - IntersectionArea(circle1, circle2);
}

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

template<typename T, typename U>
bool IsContainsPoints(const Circle<T> &c, const vector<Point<U>> &pts) {
    for (auto &p: pts) {
        if (!c.isInside(p)) {
            return false;
        }
    }
    return true;
}

template<typename T>
Circle<ld> MinCircle(vector<Point<T>> &pts) {
    int n = pts.size();
    Circle<ld> C(pts[0], (ld) 0);
    for (int i = 1; i < n; i++) {
        if (!C.isInside(pts[i])) {
            C = Circle<ld>(pts[i], (ld) 0);
            for (int j = 0; j < i; j++) {
                if (!C.isInside(pts[j])) {
                    C = Circle<ld>(pts[i], pts[j]);
                    for (int k = 0; k < j; k++) {
                        if (!C.isInside(pts[k])) {
                            C = Circle<ld>(pts[i], pts[j], pts[k]);
                        }
                    }
                }
            }
        }
    }
    return C;
}


template<typename T>
vector<Point<T>> ConvexHull(vector<Point<T>> pts) {
    int min_idx = min_element(all(pts)) - pts.begin();
    swap(pts[0], pts[min_idx]);

    sort(pts.begin() + 1, pts.end(), [&](const Point<T> &a, const Point<T> &b) {
        auto val = (a - pts[0]) * (b - pts[0]);
        if (val != 0) return val > 0;
        return dist2(a, pts[0]) < dist2(b, pts[0]);
    });
    vector<Point<T>> convex_hull = {pts[0]};
    int sz = 0;
    for (int i = 1; i < (int) pts.size(); ++i) {
        while (sz && LessOrEqual((convex_hull[sz] - convex_hull[sz - 1]) * (pts[i] - convex_hull[sz]), 0)) {
            convex_hull.pop_back();
            --sz;
        }
        convex_hull.push_back(pts[i]);
        ++sz;
    }
    return convex_hull;
}

template<typename T, typename U>
bool VComp(const Point<T> &a, const Point<U> &b) {
    bool upA = a.y > 0 || (a.y == 0 && a.x >= 0);
    bool upB = b.y > 0 || (b.y == 0 && b.x >= 0);
    if (upA != upB) return upA;
    auto val = a * b;
    if (val != 0) return val > 0;
    return len2(a) < len2(b);
}

template<typename T, typename U>
bool VCompNoLen(const Point<T> &a, const Point<U> &b) {
    bool upA = a.y > 0 || (a.y == 0 && a.x >= 0);
    bool upB = b.y > 0 || (b.y == 0 && b.x >= 0);
    if (upA != upB) return upA;
    auto val = a * b;
    return val > 0;
}

template<typename T>
T SignedArea(vector<Point<T>> &pts) {
    int n = pts.size();
    T res = 0;
    rep(i, n) {
        res += pts[i] * pts[(i + 1) % n];
    }
    return res;
}

template<typename T>
T Area(vector<Point<T>> &pts) {
    return abs(SignedArea(pts));
}


template<typename T>
void NormalizeConvexPoly(vector<Point<T>> &A) {
    if (SignedArea(A) < 0) {
        reverse(all(A));
    }
    int min_idx = min_element(all(A), [&](const Point<T> &a, const Point<T> &b) {
        return make_pair(a.y, a.x) < make_pair(b.y, b.x);
    }) - A.begin();
    rotate(A.begin(), A.begin() + min_idx, A.end());
}

template<typename T>
vector<Point<T>> MinkowskiSum(vector<Point<T>> A, vector<Point<T>> B) {
    NormalizeConvexPoly(A);
    NormalizeConvexPoly(B);
    if (A.empty()) return B;
    if (B.empty()) return A;
    Point<T> S = A[0] + B[0];
    vector<Point<T>> edges;
    int n = A.size(), m = B.size();
    rep(i, n) edges.push_back(A[(i + 1) % n] - A[i]);
    rep(i, m) edges.push_back(B[(i + 1) % m] - B[i]);
    sort(all(edges), VComp<T, T>);
    rotate(edges.begin(), edges.end() - 1, edges.end());
    edges[0] = S;
    for (int i = 1; i < edges.size(); ++i) {
        edges[i] += edges[i - 1];
    }
    return edges;
}

template<typename T>
ld DistConvexPolygons(const vector<Point<T>> &A, vector<Point<T>> B) {
    for (auto &p: B) p = -p;
    auto C = MinkowskiSum(A, B);
    NormalizeConvexPoly(C);
    int n = C.size();
    bool ok = true;
    rep(i, n) ok &= ((C[i] * C[(i + 1) % n]) >= 0);
    if (ok) return 0;
    Point<T> mid(0, 0);
    ld d = dist(mid, C[0]);
    rep(i, n) d = min(d, Dist(mid, Segment(C[(i + 1) % n], C[i])));
    return d;
}


template<typename T, typename U>
pair<int, int> GetTangents(const vector<Point<T>> &poly, const Line<U> &line) {
    int n = poly.size();
    auto start = line.GetValue(poly[0]);
    bool isUp = line.GetValue(poly[1]) >= start;
    pair<int, int> result = {-1, -1};
    if (isUp) {
        result.first = FindLastFalse(0, n, [&](const int &i) {
            if (!i) return false;
            auto val = line.GetValue(poly[i]);
            if (val < start) return true;
            auto valp = line.GetValue(poly[i - 1]);
            if (valp > val) return true;
            return false;
        });
        result.second = FindLastFalse(0, n, [&](const int &i) {
            if (i <= 1) return false;
            auto val = line.GetValue(poly[i]);
            if (val >= start) return false;
            auto valp = line.GetValue(poly[i - 1]);
            if (valp < val) return true;
            return false;
        });
    } else {
        result.first = FindLastFalse(0, n, [&](const int &i) {
            if (i <= 1) return false;
            auto val = line.GetValue(poly[i]);
            if (val <= start) return false;
            auto valp = line.GetValue(poly[i - 1]);
            if (valp > val) return true;
            return false;
        });
        result.second = FindLastFalse(0, n, [&](const int &i) {
            if (!i) return false;
            auto val = line.GetValue(poly[i]);
            if (val > start) return true;
            auto valp = line.GetValue(poly[i - 1]);
            if (valp < val) return true;
            return false;
        });
    }
    for (int i: {0, 1, n - 2, n - 1}) {
        if (i < 0 || i >= (int) poly.size()) continue;
        if (line.GetValue(poly[result.first]) < line.GetValue(poly[i])) result.first = i;
        if (line.GetValue(poly[result.second]) > line.GetValue(poly[i])) result.second = i;
    }
    return result;
}

template<typename T, typename U>
pair<int, int> GetTangents(const vector<Point<T>> &poly, const Point<U> &P) {
    int n = poly.size();
    auto GetDirection = [&](int i, int j) {
        if (i < 0) i += n;
        if (j < 0) j += n;
        if (i >= n) i -= n;
        if (j >= n) j -= n;
        if (i == j) return 0;
        auto val = (poly[i] - P) * (poly[j] - P);
        if (val > 0) return -2;
        if (val < 0) return 2;
        auto q = dist2(poly[i], P) - dist2(poly[j], P);
        if (q > 0) return -1;
        if (q < 0) return 1;
        assert(false);
        return 0;
    };
    ll d01 = GetDirection(0, 1);
    pair<int, int> result = {-1, -1};
    if (d01 == -1) {
        result.first = 0;
    } else if (d01 == -2) {
        result.first = FindFirstTrue(0, n, [&](const int &i) {
            if (!i) return false;
            if (GetDirection(0, i) >= -1) return true;
            if (GetDirection(i, i + 1) == -2) return false;
            return true;
        }) % n;
    } else {
        assert(d01 == 1 || d01 == 2);
        result.first = FindFirstTrue(0, n, [&](const int &i) {
            ll v = GetDirection(0, i);
            assert(v != -1);
            if (v >= 2) return false;
            if (GetDirection(i, i + 1) == -2) return false;
            return true;
        }) % n;
    }
    assert(GetDirection(result.first, result.first + 1) >= -1 && GetDirection(result.first, result.first - 1) >= -1);
    if (d01 == 1) {
        result.second = 1;
    } else if (d01 == 2) {
        result.second = FindFirstTrue(0, n, [&](const int &i) {
            if (!i) return false;
            if (GetDirection(0, i) <= 1) return true;
            if (GetDirection(i, i + 1) >= 1) return false;
            return true;
        }) % n;
    } else {
        assert(d01 == -1 || d01 == -2);
        result.second = FindFirstTrue(0, n, [&](const int &i) {
            if (!i) return false;
            ll v = GetDirection(0, i);
            assert(v != 1);
            if (v <= -2) return false;
            if (GetDirection(i, i + 1) >= 1) return false;
            return true;
        }) % n;
    }
    assert(GetDirection(result.second, result.second + 1) <= 1 && GetDirection(result.second, result.second - 1) <= 1);
    return result;
}

ll read_ll(ll cnt = 12) {
    ll x = 0;
    string s; cin >> s;
    int cur = 0;
    bool was = false;
    for(auto &c : s) {
        if (c == '.') {
            was = true;
            continue;
        }
        x *= 10;
        x += c - '0';
        if (was) cur++;
    }
    while (cur < cnt) {
        x *= 10;
        cur++;
    }
    return x;
}

using int128 = __int128;

const ll M = 1e12;

struct Poly {
    vector<ptd> a;
    vector<int128> l;
    vector<pt> b;
    vector<ptd> c;

    void read() {
        int m; cin >> m;
        a.resize(m);
        b.resize(m);
        rep(i, m) {
            ll x = read_ll();
            ll y = read_ll();
            b[i] = {x, y};
            a[i] = {(ld)x / M, (ld)y / M};
        }
        c.resize(m);
        l.resize(m);
        rep(i, m) {
            ll dx = b[(i + 1) % m].x - b[i].x;
            ll dy = b[(i + 1) % m].y - b[i].y;
            l[i] = (int128)dx * dx + (int128)dy * dy;
        }
    }
};

ptd rotateccw(ptd a, double t) { return ptd(a.x * cos(t) - a.y * sin(t), a.x * sin(t) + a.y * cos(t)); }
ptd rotatecw(ptd a, double t) { return ptd(a.x * cos(t) + a.y * sin(t), -a.x * sin(t) + a.y * cos(t)); }

ptd GetC(ptd a, ptd b, ptd c, ptd a_new, ptd b_new) {
    ptd ab = b - a;
    ptd ab_new = b_new - a_new;

    ld ang1 = atan2(ab.y, ab.x);
    ld ang2 = atan2(ab_new.y, ab_new.x);

    ld ang = ang2 - ang1;

    ptd bc = c - b;
    ptd bc_new = rotateccw(bc, ang);

    return b_new + bc_new;
}

void solve() {
    int n; cin >> n;
    vector<Poly> p(n);
    vector<pair<int128, pi>> kek;
    rep(i, n) {
        p[i].read();
        rep(j, p[i].l.size()) kek.push_back({p[i].l[j], {i, j}});
    }
    sort(all(kek));
    ll MX = 1e12;
    int l = 0;
    int cnt1 = 0;
    int cnt2 = 0;
    vector<vector<vector<pair<int, int>>>> g(n);
    rep(i, n) {
        g[i].resize(p[i].l.size());
    }

    int128 SKIP = 1e12;
    SKIP *= SKIP;
    while (l < kek.size()) {
        if (l + 1 < kek.size() && kek[l].first != SKIP && kek[l + 1].first - MX <= kek[l].first) {
            auto [i1, j1] = kek[l].second;
            auto [i2, j2] = kek[l + 1].second;
            g[i1][j1].emplace_back(i2, j2);
            g[i2][j2].emplace_back(i1, j1);

            l += 2;
            cnt2++;
            continue;
        }
        cnt1++;
        l++;
    }

    pair<int, int> st = {-1, -1};
    rep(i, n) {
        int sz = p[i].l.size();
        rep(j, p[i].l.size()) {
            if (!g[i][j].empty()) continue;
            int j1 = j - 1;
            if (j1 < 0) j1 += p[i].l.size();
            if (!g[i][j1].empty()) continue;

            auto v1 = p[i].b[(j + 1) % sz] - p[i].b[j];
            auto v2 = p[i].b[j % sz] - p[i].b[j1];
            int128 skalar = (int128)v1.x * v2.x + (int128)v1.y * v2.y;
            if (skalar < 0) skalar = -skalar;
            if (skalar >= MX) continue;

//            int128 vect = (int128)v1.x * v2.y - (int128)v1.y * v2.x;
//            if (vect > MX) continue;

            st = {i, j};
            break;
        }
        if (st.first != -1) break;
    }

    vector<vector<bool>> used(n);
    rep(i, n) used[i].resize(g[i].size(), false);

    function<void(int, int, ptd, ptd)> dfs = [&] (int i, int j, ptd p1, ptd q1) {
        assert(0 <= i && i < n);
        int sz = p[i].b.size();
        rep(_, p[i].b.size()) {
            if (!used[i][j]) {
                used[i][j] = true;
                p[i].c[j] = p1;
                for (auto &[i2, j2]: g[i][j]) {
                    if (used[i2][j2]) continue;
                    dfs(i2, j2, q1, p1);
                }
            }
            // p1 - a[j]
            // q1 - a[j + 1]

            ptd nx = GetC(p[i].a[j], p[i].a[(j + 1) % sz], p[i].a[(j + 2) % sz], p1, q1);
            p1 = q1;
            q1 = nx;
            j = (j + 1) % sz;
        }
    };

    {
        if (st.first == -1) {
            vi kek;
            while (true) {
                kek.push_back(1);
                if (kek.back() == 228) {
                    break;
                }
            }
            return;
        }
        auto [i, j] = st;
        ptd p1 = {0, 0};
        ptd q1 = {len((p[i].a[(j + 1) % p[i].b.size()] - p[i].a[j])), 0};
        dfs(i, j, p1, q1);
    }

    rep(i, n) {
        rep(j, p[i].c.size()) {
            cout << p[i].c[j] << '\n';
        }
        cout << '\n';
    }
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout << setprecision(12) << fixed;
    int t = 1;


//    cin >> t;
    rep(i, t) {
        solve();
    }

    return 0;
}

詳細信息

Test #1:

score: 100
Accepted
time: 0ms
memory: 4224kb

input:

4
4
0.440405375916 0.778474079786
0.000000000000 0.090337001520
0.469097990019 0.000000000000
0.702887505082 0.689470121906
4
0.222810526978 0.000000000000
0.270828246634 0.522212063829
0.000000000000 0.547114887265
0.021480010612 0.069880870008
4
0.000000000000 0.312825941471
0.358219176380 0.00000...

output:

0.277161636324 0.000000000000
0.473262431362 0.793116644515
0.000000000005 0.728029248280
0.000000000000 0.000000000000

0.524415046517 0.999999999999
0.000000000004 0.999999999998
0.000000000005 0.728029248280
0.473262431362 0.793116644515

1.000000000004 0.999999999997
0.524415046517 0.99999999999...

result:

ok OK

Test #2:

score: -100
Memory Limit Exceeded

input:

2
4
1.187724454426 0.260257896229
0.903481480651 1.219010174901
0.000000000000 0.951153431795
0.309873903757 0.000000000000
4
0.516015116935 0.888042716318
0.000000000000 0.031046166652
0.048574738349 0.000000000000
0.587115596943 0.842599396881

output:


result: