2019雅礼集训 D4T3 n [咕咕咕]

题目描述:

样例:

input:
4 2
0 0
0 1
1 1
1 0

output:
1.0000000000

数据范围与约定:

标签:计算几何(吧,不是很懂)

题解:

全场唯一AC代码:

#include <bits/stdc++.h>
 
using std::pair;
using std::vector;
using std::string;

typedef long long ll;
typedef pair<int, int> pii;
 
#define fst first
#define snd second
#define pb(a) push_back(a)
#define mp(a, b) std::make_pair(a, b)
#define debug(...) fprintf(stderr, __VA_ARGS__)
 
template <typename T> bool chkmax(T& a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> bool chkmin(T& a, T b) { return a > b ? a = b, 1 : 0; }
 
const int N = 100000;
const int oo = 0x3f3f3f3f;
 
template<typename T> T read(T& x) {
    int f = 1; x = 0;
    char ch = getchar();
    for(;!isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; 
    return x *= f;
}

const double eps = 1e-9;

typedef struct Point {
    double x, y;
    Point() { }
    Point(double x_, double y_): x(x_), y(y_) { }
} Vector;

Point operator - (const Point& a, const Point& b) { return Point(a.x - b.x, a.y - b.y); }
Point operator + (const Point& a, const Point& b) { return Point(a.x + b.x, a.y + b.y); }
Point operator * (const Point& a, const double&b) { return Point(a.x * b, a.y * b); }
Point operator / (const Point& a, const double&b) { return Point(a.x / b, a.y / b); }

double dot(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y; }
double len(const Point& a) { return sqrt(dot(a, a)); }
Point unit(const Point& a) { return a / len(a); }


double T;
int n, m;
Point p[N + 5];

typedef pair<int, double> pid;
typedef pair<double, double> pdd;

int dcmp(double x) {
    return (x > -eps) - (x < eps);
}

vector<pdd> solve(double a, double b, double c) {
    static vector<pdd> res;

    res.clear();
    if(dcmp(a) == 0) {
        if(dcmp(b) == 0) {
            if(dcmp(c) <= 0) {
                res.pb(mp(-1e9, 1e9));
            }
            return res;
        }

        if(dcmp(b) > 0) {
            res.pb(mp(-1e9, -c / b));
        } else {
            res.pb(mp(-c / b, 1e9));
        }
        return res;
    }

    double delta = b * b - 4 * a * c;

    if(dcmp(delta) < 0) {
        if(dcmp(a) < 0) {
            res.pb(mp(-1e9, 1e9));
        }
        return res;
    }

    double x0 = (- b - sqrt(delta)) / (2*a), x1 = (- b + sqrt(delta)) / (2*a);
    if(x0 > x1) std::swap(x0, x1);

    if(dcmp(a) > 0) { 
        res.pb(mp(x0, x1)); 
    } else {
        res.pb(mp(-1e9, x0));
        res.pb(mp(x1, 1e9));
    }

    return res;
}

#define nxt(x) ((x + 1) % n)

vector<pdd> range;
void get_range(double l) {

    range.clear();
    double t = T / m;
    pid a = mp(0, len(p[1]-p[0])), b;
    for(int i = 0; i < n; ++i) {
        double l_ = len(p[nxt(i)] - p[i]);
        if(l_ < t) t -= l_; else { b = mp(i, l_ - t); break; }
    }

    t = 0;
    while(a.fst < n) {
        Point va = unit(p[nxt(a.fst)] - p[a.fst]);
        Point vb = unit(p[nxt(b.fst)] - p[b.fst]);
        Point pa = p[nxt(a.fst)] + unit(p[a.fst] - p[nxt(a.fst)]) * a.snd;
        Point pb = p[nxt(b.fst)] + unit(p[b.fst] - p[nxt(b.fst)]) * b.snd;

        double d = std::min(a.snd, b.snd); a.snd -= d, b.snd -= d;
        if(!dcmp(a.snd)) a.fst = a.fst + 1 , a.snd = len(p[nxt(a.fst)] - p[a.fst]);
        if(!dcmp(b.snd)) b.fst = nxt(b.fst), b.snd = len(p[nxt(b.fst)] - p[b.fst]);

        static vector<pdd> sol;
        sol = solve(dot(va-vb, va-vb), 2.*dot(pa-pb, va-vb), dot(pa-pb, pa-pb) - l*l);

        for(int i = 0; i < int(sol.size()); ++i) {
            pdd tmp = sol[i];
            chkmax(tmp.fst, 0.); chkmin(tmp.snd, d);

            if(tmp.fst <= tmp.snd) {
                range.pb(mp(tmp.fst + t, tmp.snd + t));
            }
        }
        t += d;
    }

    //for(auto x : range) { printf("%lf %lf\n", x.fst, x.snd); }
}

bool chk(double l) {
    get_range(l);
    static vector<pdd> can;
    static vector<double> pos;

    for(int i = 1; i < int(range.size()); ++i) {
        if(range[i].fst < range[i-1].snd + 1e-6) range[i].fst += 1e-6;
    }
    vector<pdd>::iterator it = range.begin();

    can.clear();
    pos.clear();
    for(int i = 1; i <= m; ++i) {
        double L = (i-1)*T / m, R = i*T / m;
        for(; it != range.end() && (*it).fst <= i*T / m; ) {
            double x = std::max((*it).fst, L);
            double y = std::min((*it).snd, R);
            
            can.pb(mp(x-L, y-L));
            pos.pb(x-L), pos.pb(y-L);
            if((*it).snd <= i*T / m + eps) ++ it; else break;
        }
    }

    static int cnt; cnt = 0;
    static double q[N*4 + 5];

    std::sort(pos.begin(), pos.end());
    std::sort(can.begin(), can.end());

    it = can.begin();
    for(int i = 0; i < int(pos.size()); ++i) {
        while(it != can.end() && (*it).fst <= pos[i]) {
            q[cnt ++] = (*it).snd; ++ it;
            std::push_heap(q, q + cnt, std::greater<double>()); 
        }

        while(cnt && q[0] < pos[i]) {
            std::pop_heap(q, q + (cnt--), std::greater<double>());
        }

        if(cnt >= m) return true;
    }
    return false;
}

int main() {
    freopen("n.in", "r", stdin);
    freopen("n.out", "w", stdout);
    
    read(n), read(m);
    for(int i = 0; i < n; ++i) {
        static int x, y;
        read(x), read(y);
        p[i] = Point(x, y);
    }
    for(int i = 0; i < n; ++i) T += len(p[nxt(i)] - p[i]); 
    
    int TIMES = 50;
    double l = 0, r = 4000;

    for(; TIMES--; ) {
        double mid = (l + r) / 2.0;
        if(chk(mid)) r = mid; else l = mid;
    }
    printf("%.10lf\n", r);

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/p-b-p-b/p/10246542.html