列表

详情


NC218872. Mocha的多边形

描述

Mocha 在时空漩涡中发现了一个魔法凸多边形,她想要和你分享这个多边形。因此她决定使用魔法将多边形切割为面积相等的两部分,然而 Mocha 刚从时空漩涡中回来,并没有许多魔力,所以她只能切割一次,请你帮她计算出切割多边形产生切痕的最短长度。

输入描述

第一行一个正整数  (),表示凸多边形的边数。
接下来  行,每行两个整数 x_i,y_i (),分别为凸多边形每个顶点的横坐标与纵坐标。保证点坐标按逆时针顺序输入。

输出描述

输出一个正实数,代表最短切痕长度,你的答案被认定为正确当且仅当你的答案与真实答案的绝对误差或相对误差不超过 

示例1

输入:

4
0 0
2 0
2 2
0 2

输出:

2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 468ms, 内存消耗: 1272K, 提交时间: 2021-05-09 21:23:59

#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
using namespace std;

typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef long long ll;

template <typename T>
inline void read(T &f) {
    f = 0; T fu = 1; char c = getchar();
    while (c < '0' || c > '9') { if (c == '-') { fu = -1; } c = getchar(); }
    while (c >= '0' && c <= '9') { f = (f << 3) + (f << 1) + (c & 15); c = getchar(); }
    f *= fu;
}

template <typename T>
void print(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x < 10) putchar(x + 48);
    else print(x / 10), putchar(x % 10 + 48);
}

template <typename T>
void print(T x, char t) {
    print(x); putchar(t);
}

const int N = 1e5 + 5;

struct point_t {
    int x, y;
    point_t (int a = 0, int b = 0) : x(a), y(b) {}
} a[N];

point_t operator - (const point_t a, const point_t b) {
    return point_t(a.x - b.x, a.y - b.y);
}

long double ans = 1e50;
ll all, now;
int n;

ll cross(point_t a, point_t b) {
    return 1ll * a.x * b.y - 1ll * a.y * b.x;
}

ll area2(int i, int j, int k) {
    return abs(cross(a[j] - a[i], a[k] - a[i]));
}

long double cross(long double a, long double b, long double c, long double d) {
    return a * d - b * c;
}

void calc(int i, int j) {
    long double l, r;
    point_t vi = a[i % n + 1] - a[i], vj = a[j % n + 1] - a[j];
    ll ai = area2(i, i % n + 1, j);
    ll aj = area2(i % n + 1, j, j % n + 1);
    ll ij = area2(i, i % n + 1, j % n + 1);
    // fprintf(stderr, "ai = %lld, aj = %lld\n", ai, aj);
    if (now * 2 <= all) l = 0;
    else l = (long double)(now * 2 - all) / 2 / ai;
    if ((now - ai + aj) * 2 >= all) r = 1;
    else r = 1 - (long double)(all - (now - ai + aj) * 2) / 2 / ij;
    // fprintf(stderr, "now = %lld, l = %.10lf, r = %.10lf\n", now, (double)l, (double)r);
    auto calc = [&](long double pos) {
        long double x = a[i].x + pos * vi.x;
        long double y = a[i].y + pos * vi.y;
        long double _now = now - ai * pos;
        long double areaj = fabs(cross(a[j].x - x, a[j].y - y, a[j % n + 1].x - x, a[j % n + 1].y - y));
        long double k = (all - _now * 2) / 2 / areaj;
        long double _x = a[j].x + vj.x * k;
        long double _y = a[j].y + vj.y * k;
        return (x - _x) * (x - _x) + (y - _y) * (y - _y);
    };
    while (r - l > 1e-10) {
        long double mid1 = l + (r - l) / 3;
        long double mid2 = r - (r - l) / 3;
        if (calc(mid1) < calc(mid2)) r = mid2;
        else l = mid1;
    }
    ans = min(ans, calc((l + r) / 2));
    // fprintf(stderr, "i = %d, j = %d, l = %.10lf, r = %.10lf, calc = %.10lf\n", i, j, (double)l, (double)r, (double)calc((l + r) / 2));
}

int main() {
    read(n);
    for (int i = 1; i <= n; i++) read(a[i].x), read(a[i].y);
    for (int i = 2; i < n; i++) all += area2(1, i, i + 1);
    for (int i = 1, j = 2; i <= n; ) {
        while ((now + area2(i, j, j % n + 1)) * 2 < all) {
            now += area2(i, j, j % n + 1);
            j = j % n + 1;
        }
        calc(i, j);
        if ((now + area2(i, j, j % n + 1) - area2(i, i % n + 1, j % n + 1)) * 2 > all) {
            now -= area2(i, i % n + 1, j);
            ++i;
        } else {
            now += area2(i, j, j % n + 1);
            j = j % n + 1;
        }
    }
    printf("%.10lf\n", (double)sqrt(ans));
    return 0;
}

上一题