QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#34625#4226. Cookie CutterYaoBIGWA 5662ms4012kbC++178.0kb2022-06-12 01:27:182022-06-12 01:27:20

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-12 01:27:20]
  • 评测
  • 测评结果:WA
  • 用时:5662ms
  • 内存:4012kb
  • [2022-06-12 01:27:18]
  • 提交

answer

#include "bits/stdc++.h"
#define rep(i, a, n) for (auto i = a; i <= (n); i++)
#define revrep(i, a, n) for (auto i = n; i >= (a); i--)
#define pb push_back
#define mp make_pair
#define FI first
#define SE second
#define all(a) a.begin(), a.end()
#define sz(a) (int)(a).size()
template<class T> inline bool chmax(T &a, T b) { if(a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T &a, T b) { if(b < a) { a = b; return 1; } return 0; }
using namespace std;

template<class A, class B> string to_string(pair<A, B> p);
string to_string(const string &s) { return '"' + s + '"'; }
string to_string(const char *s) { return to_string((string) s); }
string to_string(char c) { return "'" + string(1, c) + "'"; }
string to_string(bool x) { return x ? "true" : "false"; }
template<class A> string to_string(A v) {
    bool first = 1;
    string res = "{";
    for (const auto &x: v) {
        if (!first) res += ", ";
        first = 0;
        res += to_string(x);
    }
    res += "}";
    return res;
}
template<class A, class B> string to_string(pair<A, B> p) { return "(" + to_string(p.FI) + ", " + to_string(p.SE) + ")"; }

void debug_out() { cerr << endl; }
template<class Head, class... Tail> void debug_out(Head H, Tail... T) {
    cerr << " " << to_string(H);
    debug_out(T...);
}
#ifndef ONLINE_JUDGE
    #define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
    #define debug(...) if(0) puts("No effect.")
#endif

using ll = long long;
// using LL = __int128;
using pii = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vi>;
using db = double;
using ldb = long double;

const int inf = 0x3f3f3f3f;

template<class T> struct TPoint {
    // use T = double or T = long long.   
    using P = TPoint;
    static constexpr T eps = static_cast<T>(1e-9);
    static int sgn(T x) { return (x > eps) - (x < -eps); }
    static int cmp(T x, T y) { return sgn(x - y); }
    static T sqr(T x) { return x * x; }

    T x, y;

    P operator +(P a) const { return P{x + a.x, y + a.y}; }
    P operator -(P a) const { return P{x - a.x, y - a.y}; }
    P operator *(T a) const { return P{x * a, y * a}; }
    P operator /(T a) const { return P{x / a, y / a}; }
    bool operator ==(P a) const { return cmp(x, a.x) == 0 && cmp(y, a.y) == 0; }
    bool operator <(P a) const { return cmp(x, a.x) == 0 ? cmp(y, a.y) < 0: x < a.x; }

    T len() const { return sqrt(sqr(x) + sqr(y)); } // I believe that you should not use this function when T = long long.
    T dis_to(P a) const { return (*this - a).len(); }
    T len2() const { return sqr(x) + sqr(y); }
    P unit() const {
        if (eps != 0) return len() <= eps ? P{} : *this / len(); // for float.
        else return *this; // for long long
    }

    T dot(P b) const { return x * b.x + y * b.y; }
    T cross(P b) const { return x * b.y - y * b.x; }
    bool is_upper() const { return y > eps || (sgn(y) == 0 && x < -eps); }
    static int cmp_polar(const P &a, const P &b) {
        if (a.is_upper() != b.is_upper()) return a.is_upper() < b.is_upper();
        return a.unit().cross(b.unit()) > eps;
        // Taking unit makes it slower but I believe it is also safer. You can drop .unit() when you think the precision is not an issue.
        // atan2 is much slower.
    }
    P rot90() { return P{-y, x}; }

    P rotate(db theta) const {
        P a{cos(theta), sin(theta)};
        return P{x * a.x - y * a.y, x * a.y + y * a.x};
    }
    T project_len(P a, P b) const { return (*this - a).dot((b - a).unit()); } // signed.
    T dis_to_line(P a, P b) const { return (*this - a).cross((b - a).unit()); } // signed, return 0 if a == b.
    T dis_to_seg(P a, P b) const {
        if (project_len(a, b) < -eps) return (*this - a).len();
        if (project_len(b, a) < -eps) return (*this - b).len();
        return fabs(dis_to_line(a, b));
    }
    P project_to_line(P a, P b) const { return a + (b - a) * project_len(a, b); }
    bool on_seg(P a, P b) const { return dis_to_seg(a, b) <= eps; } // including vertice a and b.
    bool on_line(P a, P b) const { return sgn(dis_to_line(a, b)) == 0; }
};

using T = db;
using P = TPoint<T>;

string to_string(const P& p) { return "(" + to_string(p.x) + ", " + to_string(p.y) + ")"; }

T Area(const vector<P> &poly) {
    if (poly.empty()) return 0;
    T sum = 0;
    rep(i, 0, sz(poly) - 1) sum += (poly[i] - poly[0]).cross(poly[(i + 1) % sz(poly)] - poly[0]);
    return sum / 2;
}

struct L {
    P a, b;
    P& operator[](int i) const { return i == 0 ? (P&)a : (P&)b; }
    P dir() const { return b - a; }
    bool include(P p) const { return p.dis_to_line(a, b) < -P::eps; }
    bool operator <(const L &rhs) const { return P::cmp_polar(dir(), rhs.dir()); }
    pair<int, P> intersect(const L &rhs) const {
        auto s0 = (a - rhs[0]).cross(rhs.dir());
        auto s1 = (b - rhs[0]).cross(rhs.dir());
        if(P::cmp(s0, s1) == 0) return mp(0, P{});
        return mp(1, (b * s0 - a * s1) / (s0 - s1));
    }
};

vector<P> HPI(vector<L> ls) {
    // please make sure l is closed.   
    auto Samedir = [](L r, L s) { return (r < s || s < r) == 0; };
    sort(all(ls), [&](L r, L s) { return Samedir(r, s) ? s.include(r[0]) : r < s; });

    // assuming l is closed then the intersect function should be fine.
    auto check = [](L w, L r, L s) {
        auto [res, p] = r.intersect(s);
        if (res == 0) return false; // if r and s are parallel then it implies Area of intersection should be 0.
        return w.include(p);
    };
    
    deque<L> q;
    rep(i, 0, sz(ls) - 1) {
        if (i && Samedir(ls[i], ls[i - 1])) continue;
        while (sz(q) > 1 && !check(ls[i], q.end()[-2], q.back())) q.pop_back();
        while (sz(q) > 1 && !check(ls[i], q[0], q[1])) q.pop_front();
        q.pb(ls[i]);
    }
    while (sz(q) > 2 && !check(q[0], q.end()[-2], q.back())) q.pop_back();
    while (sz(q) > 2 && !check(q.back(), q[0], q[1])) q.pop_front();
    vector<P> res;
    rep(i, 0, sz(q) - 1) res.pb(q[i].intersect(q[(i + 1) % sz(q)]).SE);
    return res;
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    
    db ans = -1e100;
    int w, n; cin >> w >> n;

    vector<P> corners{P{0, 0}, P{w, 0}, P{w, w}, P{0, w}};
    vector<L> borders;
    rep(i, 0, 3) borders.pb(L{corners[i], corners[(i + 1) % 4]});

    vector<P> ps(n);
    for (auto &[x, y]: ps) cin >> x >> y;

    for (auto o: ps) {
        vector<P> vec = corners;
        for (auto p: ps) if (!(p == o)) vec.pb(p);

        sort(all(vec), [&](P p, P q) { return P::cmp_polar(p - o, q - o); });
        int N = sz(vec);
        
        auto next = [&](int now) { return now + 1 == N ? 0 : now + 1; };
        auto inside = [&](P p) { return p.x > P::eps && p.x < w - P::eps && p.y > P::eps && p.y < w - P::eps; };

        int last = 0;
        revrep(i, 1, N - 1) if (vec[i].dis_to_line(o, vec[0]) >= -P::eps) last = i;
        int cnt = 1;
        if (last > 0) rep(i, last, N - 1) cnt += inside(vec[i]);

        rep(i, 0, N - 1) {
            P p = vec[i];
            cnt += inside(p);
            while (vec[last].dis_to_line(o, p) < -P::eps) {
                cnt -= inside(vec[last]);
                last = next(last);
            }
            vector<L> ls = borders; ls.pb(L{p, o});
            T area = Area(HPI(ls));
            // debug(cnt, area, o, p, (db)cnt / n - area / w / w);
            chmax(ans, (db)cnt / n - area / w / w);
        }
    }

    auto solve = [&]() {
        for (auto p: ps) {
            auto [x, y] = p;
            if (P::cmp(x * 2, w) <= 0 && P::cmp(y * 2, w) <= 0) {
                P q{x * 2, 0};
                int cnt = 0;
                for(auto a: ps) if (a.dis_to_line(p, q) >= -P::eps) cnt++;
                chmax(ans, (db)cnt / n - 2.0 * x * y / w / w);
            }
        }
    };
    rep(i, 1, 4) {
        solve();
        for (auto &p: ps) p = P{w - p.y, p.x};
    }
    printf("%.10f\n", ans);
    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

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

input:

5 8
1 1
1 2
1 3
2 1
3 1
3 4
4 1
4 2

output:

0.3750000000

result:

ok found '0.3750000', expected '0.3750000', error '0.0000000'

Test #2:

score: -100
Wrong Answer
time: 5662ms
memory: 4012kb

input:

10000 2916
93 93
93 278
93 463
93 649
93 834
93 1019
93 1204
93 1389
93 1574
93 1760
93 1945
93 2130
93 2315
93 2500
93 2685
93 2871
93 3056
93 3241
93 3426
93 3611
93 3796
93 3982
93 4167
93 4352
93 4537
93 4722
93 4907
93 5093
93 5278
93 5463
93 5648
93 5833
93 6018
93 6204
93 6389
93 6574
93 6759...

output:

1.0089385460

result:

wrong answer 1st numbers differ - expected: '0.0093444', found: '1.0089385', error = '0.9995941'