Submission #671708

#TimeUsernameProblemLanguageResultExecution timeMemory
671708havingfun854Mobile (BOI12_mobile)C++11
100 / 100
739 ms43804 KiB
// https://oj.uz/problem/view/BOI12_mobile
#include <bits/stdc++.h>
using namespace std;

#define forint(i, from, toinc) for (int i = from; i <= toinc; ++i)
#define sq(x) (x)*(x)
#define all(x) x.begin(), x.end()

void fio()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
#ifdef USEFILE
    freopen("mobile.in", "r", stdin);
    freopen("mobile.out", "w", stdout);
#endif
}

/*
    some observations:

    if we have 2 towers with the same x, (x, y1) and (x, y2),
    we only need to keep the one with the smallest abs y value,
    let's say |y1| <= |y2|, then we can safely forget (x, y2), because for any
    point on the x axis, it will always be closer (<=) to (x, y1) than to (x, y2).

    we do a simple binary search on distance d to see if all points between [0,L]
    can be covered by d.

    when trying to see if the segments covers the entire [0,len] range,
    we do NOT have to sort the segments, because if a later one (one corresponding
    to a tower with greater x value) connects with the current range
    while a earlier one does not, we know from geometry that the later one
    will extend further to the right as well, making not considering the earlier one
    inconsequential. but this time, don't break when seeing a gap.
 */

struct Point {
    int x,y;
};
struct Range {
    double from, to;
    bool operator<(const Range &o) const {
        return from == o.from ? to > o.to : from < o.from;
        // same from rank the one with the larger to first
    }
};

int tcnt;                   // tower count
vector<Point> towers;
int len;                    // all points on (0,0) to (len,0) to the towers
vector<Range> ranges;
int rcnt;

void debug()
{
    cerr << "highway from (0,0) to (" << len << ",0)" << endl;

    cerr << tcnt << " towers:";
    forint(i, 0, tcnt-1) {
        cerr << " " << towers[i].x << "," << towers[i].y;
    }
    cerr << endl;

    cerr << rcnt << " ranges:";
    forint(i, 0, rcnt-1) {
        cerr << " [" << ranges[i].from << "," << ranges[i].to << "]";
    }
    cerr << endl;
}

void rdata()
{
    cin >> tcnt >> len;

    int lastx, lasty;       // lasty >= 0
    cin >> lastx >> lasty;
    lasty = abs(lasty);

    forint(i, 1, tcnt-1) {
        int x, y;
        cin >> x >> y;
        if (x != lastx) {
            towers.push_back({lastx, lasty});
            lastx = x;
            lasty = abs(y);
        } else if (abs(y) < abs(lasty)) {
            lasty = abs(y);
        }
        if (i == tcnt-1) {
            towers.push_back({lastx, lasty});
        }
    }

    tcnt = (int)towers.size();
}


bool can_cover(double d)
{
    ranges.clear();

    forint(i, 0, tcnt-1) {
        double x = towers[i].x;
        double y = towers[i].y;
        if (d > y) {
            double dx = sqrt(sq(d) - sq(y));
            if (x-dx > len || x+dx < 0) continue;
            ranges.push_back({x-dx, x+dx});
        }
    }
    rcnt = (int)ranges.size();

    // sort(all(ranges));

#ifdef DEBUG
    debug();
#endif

    double right = 0;
    forint(i, 0, rcnt-1) {
        if (ranges[i].from <= right) {
            right = max(ranges[i].to, right);
            if (right >= len) break;
        }
    }

    bool res = right >= len;
#ifdef DEBUG
    cerr << "d=" << d << " can" << (res ? "" : "not") << " cover all" << endl;
#endif
    return res;
}

inline
double d2(int i, double x)  // tower i to (x,0)
{
    return sq(towers[i].x - x) + sq(towers[i].y);
}

int main()
{
    fio();
    rdata();
#ifdef DEBUG
    debug();
#endif

    double dends2 = d2(0, 0);
    dends2 = max(dends2, d2(0, len));
    dends2 = max(dends2, d2(tcnt-1, 0));
    dends2 = max(dends2, d2(tcnt-1, len));

    double dmax = sqrt(dends2);

    double d = dmax+1;
    for (double step = dmax; step > 1e-4; step /= 2) {
        while (d-step > 0 && can_cover(d-step)) {
            d -= step;
        }
    }
    cout << fixed << setprecision(3) << d << '\n';

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...