QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#34625 | #4226. Cookie Cutter | YaoBIG | WA | 5662ms | 4012kb | C++17 | 8.0kb | 2022-06-12 01:27:18 | 2022-06-12 01:27:20 |
Judging History
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'